Skip to content

Commit 8e104e2

Browse files
committed
Factor out collection of overlapping ranges
1 parent 56fa0c9 commit 8e104e2

File tree

4 files changed

+60
-31
lines changed

4 files changed

+60
-31
lines changed

compiler/rustc_pattern_analysis/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ pub fn analyze_match<'p, 'tcx>(
120120

121121
let pat_column = PatternColumn::new(arms);
122122

123-
// Lint on ranges that overlap on their endpoints, which is likely a mistake.
123+
// Lint ranges that overlap on their endpoints, which is likely a mistake.
124124
lint_overlapping_range_endpoints(cx, &pat_column);
125125

126126
// Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting

compiler/rustc_pattern_analysis/src/lints.rs

+47-29
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,16 @@ use rustc_data_structures::captures::Captures;
44
use rustc_middle::ty;
55
use rustc_session::lint;
66
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
7-
use rustc_span::Span;
87

9-
use crate::constructor::{IntRange, MaybeInfiniteInt};
8+
use crate::constructor::MaybeInfiniteInt;
109
use crate::errors::{
11-
NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Overlap,
12-
OverlappingRangeEndpoints, Uncovered,
10+
self, NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Uncovered,
1311
};
1412
use crate::rustc::{
15-
Constructor, DeconstructedPat, MatchArm, MatchCtxt, PlaceCtxt, RevealedTy, RustcMatchCheckCtxt,
16-
SplitConstructorSet, WitnessPat,
13+
self, Constructor, DeconstructedPat, MatchArm, MatchCtxt, PlaceCtxt, RevealedTy,
14+
RustcMatchCheckCtxt, SplitConstructorSet, WitnessPat,
1715
};
16+
use crate::usefulness::OverlappingRanges;
1817

1918
/// A column of patterns in the matrix, where a column is the intuitive notion of "subpatterns that
2019
/// inspect the same subvalue/place".
@@ -208,34 +207,19 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
208207

209208
/// Traverse the patterns to warn the user about ranges that overlap on their endpoints.
210209
#[instrument(level = "debug", skip(cx))]
211-
pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
210+
pub(crate) fn collect_overlapping_range_endpoints<'a, 'p, 'tcx>(
212211
cx: MatchCtxt<'a, 'p, 'tcx>,
213212
column: &PatternColumn<'p, 'tcx>,
213+
overlapping_range_endpoints: &mut Vec<rustc::OverlappingRanges<'p, 'tcx>>,
214214
) {
215215
let Some(ty) = column.head_ty() else {
216216
return;
217217
};
218218
let pcx = &PlaceCtxt::new_dummy(cx, ty);
219-
let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx;
220219

221220
let set = column.analyze_ctors(pcx);
222221

223222
if matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_)) {
224-
let emit_lint = |overlap: &IntRange, this_span: Span, overlapped_spans: &[Span]| {
225-
let overlap_as_pat = rcx.hoist_pat_range(overlap, ty);
226-
let overlaps: Vec<_> = overlapped_spans
227-
.iter()
228-
.copied()
229-
.map(|span| Overlap { range: overlap_as_pat.clone(), span })
230-
.collect();
231-
rcx.tcx.emit_spanned_lint(
232-
lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
233-
rcx.match_lint_level,
234-
this_span,
235-
OverlappingRangeEndpoints { overlap: overlaps, range: this_span },
236-
);
237-
};
238-
239223
// If two ranges overlapped, the split set will contain their intersection as a singleton.
240224
let split_int_ranges = set.present.iter().filter_map(|c| c.as_int_range());
241225
for overlap_range in split_int_ranges.clone() {
@@ -248,7 +232,6 @@ pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
248232
// Iterate on patterns that contained `overlap`.
249233
for pat in column.iter() {
250234
let Constructor::IntRange(this_range) = pat.ctor() else { continue };
251-
let this_span = pat.data().unwrap().span;
252235
if this_range.is_singleton() {
253236
// Don't lint when one of the ranges is a singleton.
254237
continue;
@@ -257,16 +240,24 @@ pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
257240
// `this_range` looks like `overlap..=this_range.hi`; it overlaps with any
258241
// ranges that look like `lo..=overlap`.
259242
if !prefixes.is_empty() {
260-
emit_lint(overlap_range, this_span, &prefixes);
243+
overlapping_range_endpoints.push(OverlappingRanges {
244+
pat,
245+
overlaps_on: *overlap_range,
246+
overlaps_with: prefixes.as_slice().to_vec(),
247+
});
261248
}
262-
suffixes.push(this_span)
249+
suffixes.push(pat)
263250
} else if this_range.hi == overlap.plus_one() {
264251
// `this_range` looks like `this_range.lo..=overlap`; it overlaps with any
265252
// ranges that look like `overlap..=hi`.
266253
if !suffixes.is_empty() {
267-
emit_lint(overlap_range, this_span, &suffixes);
254+
overlapping_range_endpoints.push(OverlappingRanges {
255+
pat,
256+
overlaps_on: *overlap_range,
257+
overlaps_with: suffixes.as_slice().to_vec(),
258+
});
268259
}
269-
prefixes.push(this_span)
260+
prefixes.push(pat)
270261
}
271262
}
272263
}
@@ -275,8 +266,35 @@ pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
275266
// Recurse into the fields.
276267
for ctor in set.present {
277268
for col in column.specialize(pcx, &ctor) {
278-
lint_overlapping_range_endpoints(cx, &col);
269+
collect_overlapping_range_endpoints(cx, &col, overlapping_range_endpoints);
279270
}
280271
}
281272
}
282273
}
274+
275+
#[instrument(level = "debug", skip(cx))]
276+
pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
277+
cx: MatchCtxt<'a, 'p, 'tcx>,
278+
column: &PatternColumn<'p, 'tcx>,
279+
) {
280+
let mut overlapping_range_endpoints = Vec::new();
281+
collect_overlapping_range_endpoints(cx, column, &mut overlapping_range_endpoints);
282+
283+
let rcx = cx.tycx;
284+
for overlap in overlapping_range_endpoints {
285+
let overlap_as_pat = rcx.hoist_pat_range(&overlap.overlaps_on, overlap.pat.ty());
286+
let overlaps: Vec<_> = overlap
287+
.overlaps_with
288+
.iter()
289+
.map(|pat| pat.data().unwrap().span)
290+
.map(|span| errors::Overlap { range: overlap_as_pat.clone(), span })
291+
.collect();
292+
let pat_span = overlap.pat.data().unwrap().span;
293+
rcx.tcx.emit_spanned_lint(
294+
lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
295+
rcx.match_lint_level,
296+
pat_span,
297+
errors::OverlappingRangeEndpoints { overlap: overlaps, range: pat_span },
298+
);
299+
}
300+
}

compiler/rustc_pattern_analysis/src/rustc.rs

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ pub type DeconstructedPat<'p, 'tcx> =
3232
crate::pat::DeconstructedPat<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
3333
pub type MatchArm<'p, 'tcx> = crate::MatchArm<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
3434
pub type MatchCtxt<'a, 'p, 'tcx> = crate::MatchCtxt<'a, 'p, RustcMatchCheckCtxt<'p, 'tcx>>;
35+
pub type OverlappingRanges<'p, 'tcx> =
36+
crate::usefulness::OverlappingRanges<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
3537
pub(crate) type PlaceCtxt<'a, 'p, 'tcx> =
3638
crate::usefulness::PlaceCtxt<'a, 'p, RustcMatchCheckCtxt<'p, 'tcx>>;
3739
pub(crate) type SplitConstructorSet<'p, 'tcx> =

compiler/rustc_pattern_analysis/src/usefulness.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@ use rustc_index::bit_set::BitSet;
716716
use smallvec::{smallvec, SmallVec};
717717
use std::fmt;
718718

719-
use crate::constructor::{Constructor, ConstructorSet};
719+
use crate::constructor::{Constructor, ConstructorSet, IntRange};
720720
use crate::pat::{DeconstructedPat, WitnessPat};
721721
use crate::{Captures, MatchArm, MatchCtxt, TypeCx};
722722

@@ -1476,6 +1476,15 @@ pub enum Usefulness<'p, Cx: TypeCx> {
14761476
Redundant,
14771477
}
14781478

1479+
/// Indicates that the range `pat` overlapped with all the ranges in `overlaps_with`, where the
1480+
/// range they overlapped over is `overlaps_on`. We only detect singleton overlaps.
1481+
#[derive(Clone, Debug)]
1482+
pub struct OverlappingRanges<'p, Cx: TypeCx> {
1483+
pub pat: &'p DeconstructedPat<'p, Cx>,
1484+
pub overlaps_on: IntRange,
1485+
pub overlaps_with: Vec<&'p DeconstructedPat<'p, Cx>>,
1486+
}
1487+
14791488
/// The output of checking a match for exhaustiveness and arm usefulness.
14801489
pub struct UsefulnessReport<'p, Cx: TypeCx> {
14811490
/// For each arm of the input, whether that arm is useful after the arms above it.

0 commit comments

Comments
 (0)