Skip to content

Commit

Permalink
Run the annoying lint separately
Browse files Browse the repository at this point in the history
  • Loading branch information
Nadrieril committed Dec 22, 2020
1 parent 5a24b2c commit 7948f91
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 54 deletions.
88 changes: 36 additions & 52 deletions compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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<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![];
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<HirId>,
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,
Expand Down Expand Up @@ -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<HirId>,
) -> 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()],
Expand Down Expand Up @@ -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 }
}
Expand Down
9 changes: 7 additions & 2 deletions compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
Expand Up @@ -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);
Expand Down

0 comments on commit 7948f91

Please sign in to comment.