Skip to content

Commit 1f0daa5

Browse files
authored
Rollup merge of rust-lang#120002 - Nadrieril:dont-collect, r=compiler-errors
Lint `overlapping_ranges_endpoints` directly instead of collecting into a Vec In rust-lang#119396 I was a bit silly: I was trying to avoid any lints being fired from within the exhaustiveness algorithm for some vague aesthetic/reusability reason that doesn't really hold. This PR fixes that: instead of passing a `&mut Vec` around I just added a method to the `TypeCx` trait. r? `@compiler-errors`
2 parents bcea676 + 448c4a4 commit 1f0daa5

File tree

4 files changed

+52
-96
lines changed

4 files changed

+52
-96
lines changed

compiler/rustc_pattern_analysis/src/lib.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,9 @@ use rustc_middle::ty::Ty;
2727
#[cfg(feature = "rustc")]
2828
use rustc_span::ErrorGuaranteed;
2929

30-
use crate::constructor::{Constructor, ConstructorSet};
30+
use crate::constructor::{Constructor, ConstructorSet, IntRange};
3131
#[cfg(feature = "rustc")]
32-
use crate::lints::{
33-
lint_nonexhaustive_missing_variants, lint_overlapping_range_endpoints, PatternColumn,
34-
};
32+
use crate::lints::{lint_nonexhaustive_missing_variants, PatternColumn};
3533
use crate::pat::DeconstructedPat;
3634
#[cfg(feature = "rustc")]
3735
use crate::rustc::RustcMatchCheckCtxt;
@@ -77,6 +75,17 @@ pub trait TypeCx: Sized + fmt::Debug {
7775

7876
/// Raise a bug.
7977
fn bug(&self, fmt: fmt::Arguments<'_>) -> !;
78+
79+
/// Lint that the range `pat` overlapped with all the ranges in `overlaps_with`, where the range
80+
/// they overlapped over is `overlaps_on`. We only detect singleton overlaps.
81+
/// The default implementation does nothing.
82+
fn lint_overlapping_range_endpoints(
83+
&self,
84+
_pat: &DeconstructedPat<'_, Self>,
85+
_overlaps_on: IntRange,
86+
_overlaps_with: &[&DeconstructedPat<'_, Self>],
87+
) {
88+
}
8089
}
8190

8291
/// Context that provides information global to a match.
@@ -111,16 +120,10 @@ pub fn analyze_match<'p, 'tcx>(
111120

112121
let report = compute_match_usefulness(cx, arms, scrut_ty, scrut_validity)?;
113122

114-
let pat_column = PatternColumn::new(arms);
115-
116-
// Lint ranges that overlap on their endpoints, which is likely a mistake.
117-
if !report.overlapping_range_endpoints.is_empty() {
118-
lint_overlapping_range_endpoints(cx, &report.overlapping_range_endpoints);
119-
}
120-
121123
// Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting
122124
// `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
123125
if tycx.refutable && report.non_exhaustiveness_witnesses.is_empty() {
126+
let pat_column = PatternColumn::new(arms);
124127
lint_nonexhaustive_missing_variants(cx, arms, &pat_column, scrut_ty)?;
125128
}
126129

compiler/rustc_pattern_analysis/src/lints.rs

+3-29
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
use rustc_session::lint;
21
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
32
use rustc_span::ErrorGuaranteed;
43

5-
use crate::errors::{
6-
self, NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Uncovered,
7-
};
4+
use crate::errors::{NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Uncovered};
85
use crate::pat::PatOrWild;
96
use crate::rustc::{
10-
self, Constructor, DeconstructedPat, MatchArm, MatchCtxt, PlaceCtxt, RevealedTy,
11-
RustcMatchCheckCtxt, SplitConstructorSet, WitnessPat,
7+
Constructor, DeconstructedPat, MatchArm, MatchCtxt, PlaceCtxt, RevealedTy, RustcMatchCheckCtxt,
8+
SplitConstructorSet, WitnessPat,
129
};
1310

1411
/// A column of patterns in the matrix, where a column is the intuitive notion of "subpatterns that
@@ -196,26 +193,3 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
196193
}
197194
Ok(())
198195
}
199-
200-
pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
201-
cx: MatchCtxt<'a, 'p, 'tcx>,
202-
overlapping_range_endpoints: &[rustc::OverlappingRanges<'p, 'tcx>],
203-
) {
204-
let rcx = cx.tycx;
205-
for overlap in overlapping_range_endpoints {
206-
let overlap_as_pat = rcx.hoist_pat_range(&overlap.overlaps_on, overlap.pat.ty());
207-
let overlaps: Vec<_> = overlap
208-
.overlaps_with
209-
.iter()
210-
.map(|pat| pat.data().unwrap().span)
211-
.map(|span| errors::Overlap { range: overlap_as_pat.clone(), span })
212-
.collect();
213-
let pat_span = overlap.pat.data().unwrap().span;
214-
rcx.tcx.emit_spanned_lint(
215-
lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
216-
rcx.match_lint_level,
217-
pat_span,
218-
errors::OverlappingRangeEndpoints { overlap: overlaps, range: pat_span },
219-
);
220-
}
221-
}

compiler/rustc_pattern_analysis/src/rustc.rs

+27-10
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,26 @@
1+
use smallvec::SmallVec;
12
use std::fmt;
23
use std::iter::once;
34

45
use rustc_arena::{DroplessArena, TypedArena};
56
use rustc_data_structures::captures::Captures;
67
use rustc_hir::def_id::DefId;
78
use rustc_hir::HirId;
8-
use rustc_index::Idx;
9-
use rustc_index::IndexVec;
9+
use rustc_index::{Idx, IndexVec};
1010
use rustc_middle::middle::stability::EvalResult;
1111
use rustc_middle::mir::interpret::Scalar;
1212
use rustc_middle::mir::{self, Const};
1313
use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange, PatRangeBoundary};
1414
use rustc_middle::ty::layout::IntegerExt;
15-
use rustc_middle::ty::TypeVisitableExt;
16-
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, VariantDef};
17-
use rustc_span::ErrorGuaranteed;
18-
use rustc_span::{Span, DUMMY_SP};
15+
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeVisitableExt, VariantDef};
16+
use rustc_session::lint;
17+
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
1918
use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT};
20-
use smallvec::SmallVec;
2119

2220
use crate::constructor::{
2321
IntRange, MaybeInfiniteInt, OpaqueId, RangeEnd, Slice, SliceKind, VariantVisibility,
2422
};
25-
use crate::TypeCx;
23+
use crate::{errors, TypeCx};
2624

2725
use crate::constructor::Constructor::*;
2826

@@ -34,8 +32,6 @@ pub type DeconstructedPat<'p, 'tcx> =
3432
crate::pat::DeconstructedPat<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
3533
pub type MatchArm<'p, 'tcx> = crate::MatchArm<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
3634
pub type MatchCtxt<'a, 'p, 'tcx> = crate::MatchCtxt<'a, RustcMatchCheckCtxt<'p, 'tcx>>;
37-
pub type OverlappingRanges<'p, 'tcx> =
38-
crate::usefulness::OverlappingRanges<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
3935
pub(crate) type PlaceCtxt<'a, 'p, 'tcx> =
4036
crate::usefulness::PlaceCtxt<'a, RustcMatchCheckCtxt<'p, 'tcx>>;
4137
pub(crate) type SplitConstructorSet<'p, 'tcx> =
@@ -991,6 +987,27 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
991987
fn bug(&self, fmt: fmt::Arguments<'_>) -> ! {
992988
span_bug!(self.scrut_span, "{}", fmt)
993989
}
990+
991+
fn lint_overlapping_range_endpoints(
992+
&self,
993+
pat: &crate::pat::DeconstructedPat<'_, Self>,
994+
overlaps_on: IntRange,
995+
overlaps_with: &[&crate::pat::DeconstructedPat<'_, Self>],
996+
) {
997+
let overlap_as_pat = self.hoist_pat_range(&overlaps_on, pat.ty());
998+
let overlaps: Vec<_> = overlaps_with
999+
.iter()
1000+
.map(|pat| pat.data().unwrap().span)
1001+
.map(|span| errors::Overlap { range: overlap_as_pat.clone(), span })
1002+
.collect();
1003+
let pat_span = pat.data().unwrap().span;
1004+
self.tcx.emit_spanned_lint(
1005+
lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
1006+
self.match_lint_level,
1007+
pat_span,
1008+
errors::OverlappingRangeEndpoints { overlap: overlaps, range: pat_span },
1009+
);
1010+
}
9941011
}
9951012

9961013
/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.

compiler/rustc_pattern_analysis/src/usefulness.rs

+8-46
Original file line numberDiff line numberDiff line change
@@ -1340,10 +1340,10 @@ impl<Cx: TypeCx> WitnessMatrix<Cx> {
13401340
/// We can however get false negatives because exhaustiveness does not explore all cases. See the
13411341
/// section on relevancy at the top of the file.
13421342
fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
1343+
mcx: MatchCtxt<'_, Cx>,
13431344
overlap_range: IntRange,
13441345
matrix: &Matrix<'p, Cx>,
13451346
specialized_matrix: &Matrix<'p, Cx>,
1346-
overlapping_range_endpoints: &mut Vec<OverlappingRanges<'p, Cx>>,
13471347
) {
13481348
let overlap = overlap_range.lo;
13491349
// Ranges that look like `lo..=overlap`.
@@ -1373,11 +1373,7 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
13731373
.map(|&(_, pat)| pat)
13741374
.collect();
13751375
if !overlaps_with.is_empty() {
1376-
overlapping_range_endpoints.push(OverlappingRanges {
1377-
pat,
1378-
overlaps_on: overlap_range,
1379-
overlaps_with,
1380-
});
1376+
mcx.tycx.lint_overlapping_range_endpoints(pat, overlap_range, &overlaps_with);
13811377
}
13821378
}
13831379
suffixes.push((child_row_id, pat))
@@ -1393,11 +1389,7 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
13931389
.map(|&(_, pat)| pat)
13941390
.collect();
13951391
if !overlaps_with.is_empty() {
1396-
overlapping_range_endpoints.push(OverlappingRanges {
1397-
pat,
1398-
overlaps_on: overlap_range,
1399-
overlaps_with,
1400-
});
1392+
mcx.tycx.lint_overlapping_range_endpoints(pat, overlap_range, &overlaps_with);
14011393
}
14021394
}
14031395
prefixes.push((child_row_id, pat))
@@ -1423,7 +1415,6 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
14231415
fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
14241416
mcx: MatchCtxt<'a, Cx>,
14251417
matrix: &mut Matrix<'p, Cx>,
1426-
overlapping_range_endpoints: &mut Vec<OverlappingRanges<'p, Cx>>,
14271418
is_top_level: bool,
14281419
) -> Result<WitnessMatrix<Cx>, Cx::Error> {
14291420
debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));
@@ -1503,12 +1494,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
15031494
let ctor_is_relevant = matches!(ctor, Constructor::Missing) || missing_ctors.is_empty();
15041495
let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant);
15051496
let mut witnesses = ensure_sufficient_stack(|| {
1506-
compute_exhaustiveness_and_usefulness(
1507-
mcx,
1508-
&mut spec_matrix,
1509-
overlapping_range_endpoints,
1510-
false,
1511-
)
1497+
compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix, false)
15121498
})?;
15131499

15141500
// Transform witnesses for `spec_matrix` into witnesses for `matrix`.
@@ -1537,12 +1523,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
15371523
&& spec_matrix.rows.len() >= 2
15381524
&& spec_matrix.rows.iter().any(|row| !row.intersects.is_empty())
15391525
{
1540-
collect_overlapping_range_endpoints(
1541-
overlap_range,
1542-
matrix,
1543-
&spec_matrix,
1544-
overlapping_range_endpoints,
1545-
);
1526+
collect_overlapping_range_endpoints(mcx, overlap_range, matrix, &spec_matrix);
15461527
}
15471528
}
15481529
}
@@ -1569,23 +1550,13 @@ pub enum Usefulness<'p, Cx: TypeCx> {
15691550
Redundant,
15701551
}
15711552

1572-
/// Indicates that the range `pat` overlapped with all the ranges in `overlaps_with`, where the
1573-
/// range they overlapped over is `overlaps_on`. We only detect singleton overlaps.
1574-
#[derive(Clone, Debug)]
1575-
pub struct OverlappingRanges<'p, Cx: TypeCx> {
1576-
pub pat: &'p DeconstructedPat<'p, Cx>,
1577-
pub overlaps_on: IntRange,
1578-
pub overlaps_with: Vec<&'p DeconstructedPat<'p, Cx>>,
1579-
}
1580-
15811553
/// The output of checking a match for exhaustiveness and arm usefulness.
15821554
pub struct UsefulnessReport<'p, Cx: TypeCx> {
15831555
/// For each arm of the input, whether that arm is useful after the arms above it.
15841556
pub arm_usefulness: Vec<(MatchArm<'p, Cx>, Usefulness<'p, Cx>)>,
15851557
/// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of
15861558
/// exhaustiveness.
15871559
pub non_exhaustiveness_witnesses: Vec<WitnessPat<Cx>>,
1588-
pub overlapping_range_endpoints: Vec<OverlappingRanges<'p, Cx>>,
15891560
}
15901561

15911562
/// Computes whether a match is exhaustive and which of its arms are useful.
@@ -1596,14 +1567,9 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
15961567
scrut_ty: Cx::Ty,
15971568
scrut_validity: ValidityConstraint,
15981569
) -> Result<UsefulnessReport<'p, Cx>, Cx::Error> {
1599-
let mut overlapping_range_endpoints = Vec::new();
16001570
let mut matrix = Matrix::new(arms, scrut_ty, scrut_validity);
1601-
let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness(
1602-
cx,
1603-
&mut matrix,
1604-
&mut overlapping_range_endpoints,
1605-
true,
1606-
)?;
1571+
let non_exhaustiveness_witnesses =
1572+
compute_exhaustiveness_and_usefulness(cx, &mut matrix, true)?;
16071573

16081574
let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column();
16091575
let arm_usefulness: Vec<_> = arms
@@ -1621,9 +1587,5 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
16211587
})
16221588
.collect();
16231589

1624-
Ok(UsefulnessReport {
1625-
arm_usefulness,
1626-
non_exhaustiveness_witnesses,
1627-
overlapping_range_endpoints,
1628-
})
1590+
Ok(UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses })
16291591
}

0 commit comments

Comments
 (0)