pattern_analysis doesn't need to know what spans are

This commit is contained in:
Nadrieril 2023-12-15 16:18:21 +01:00
parent 8c5e89907c
commit 1e89a38423
6 changed files with 39 additions and 36 deletions

View file

@ -37,14 +37,17 @@ use crate::rustc::RustcMatchCheckCtxt;
use crate::usefulness::{compute_match_usefulness, ValidityConstraint};
pub trait MatchCx: Sized + Clone + fmt::Debug {
/// The type of a pattern.
type Ty: Copy + Clone + fmt::Debug; // FIXME: remove Copy
type Span: Clone + Default;
/// The index of an enum variant.
type VariantIdx: Clone + Idx;
/// A string literal
type StrLit: Clone + PartialEq + fmt::Debug;
/// Extra data to store on a match arm.
type ArmData: Copy + Clone + fmt::Debug;
/// Extra data to store on a pattern. `Default` needed when we create fictitious wildcard
/// patterns during analysis.
type PatData: Clone + Default;
fn is_opaque_ty(ty: Self::Ty) -> bool;
fn is_exhaustive_patterns_feature_on(&self) -> bool;

View file

@ -213,7 +213,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
};
use rustc_errors::DecorateLint;
let mut err = cx.tcx.sess.struct_span_warn(*arm.pat.span(), "");
let mut err = cx.tcx.sess.struct_span_warn(*arm.pat.data(), "");
err.set_primary_message(decorator.msg());
decorator.decorate_lint(&mut err);
err.emit();
@ -263,7 +263,7 @@ pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
let mut suffixes: SmallVec<[_; 1]> = Default::default();
// Iterate on patterns that contained `overlap`.
for pat in column.iter() {
let this_span = *pat.span();
let this_span = *pat.data();
let Constructor::IntRange(this_range) = pat.ctor() else { continue };
if this_range.is_singleton() {
// Don't lint when one of the ranges is a singleton.

View file

@ -26,23 +26,23 @@ pub struct DeconstructedPat<'p, Cx: MatchCx> {
ctor: Constructor<Cx>,
fields: &'p [DeconstructedPat<'p, Cx>],
ty: Cx::Ty,
span: Cx::Span,
data: Cx::PatData,
/// Whether removing this arm would change the behavior of the match expression.
useful: Cell<bool>,
}
impl<'p, Cx: MatchCx> DeconstructedPat<'p, Cx> {
pub fn wildcard(ty: Cx::Ty, span: Cx::Span) -> Self {
Self::new(Wildcard, &[], ty, span)
pub fn wildcard(ty: Cx::Ty, data: Cx::PatData) -> Self {
Self::new(Wildcard, &[], ty, data)
}
pub fn new(
ctor: Constructor<Cx>,
fields: &'p [DeconstructedPat<'p, Cx>],
ty: Cx::Ty,
span: Cx::Span,
data: Cx::PatData,
) -> Self {
DeconstructedPat { ctor, fields, ty, span, useful: Cell::new(false) }
DeconstructedPat { ctor, fields, ty, data, useful: Cell::new(false) }
}
pub(crate) fn is_or_pat(&self) -> bool {
@ -63,8 +63,8 @@ impl<'p, Cx: MatchCx> DeconstructedPat<'p, Cx> {
pub fn ty(&self) -> Cx::Ty {
self.ty
}
pub fn span(&self) -> &Cx::Span {
&self.span
pub fn data(&self) -> &Cx::PatData {
&self.data
}
pub fn iter_fields<'a>(
@ -83,7 +83,7 @@ impl<'p, Cx: MatchCx> DeconstructedPat<'p, Cx> {
let wildcard_sub_tys = || {
let tys = pcx.cx.ctor_sub_tys(other_ctor, pcx.ty);
tys.iter()
.map(|ty| DeconstructedPat::wildcard(*ty, Cx::Span::default()))
.map(|ty| DeconstructedPat::wildcard(*ty, Cx::PatData::default()))
.map(|pat| pcx.wildcard_arena.alloc(pat) as &_)
.collect()
};
@ -113,8 +113,8 @@ impl<'p, Cx: MatchCx> DeconstructedPat<'p, Cx> {
}
}
/// We keep track for each pattern if it was ever useful during the analysis. This is used
/// with `redundant_spans` to report redundant subpatterns arising from or patterns.
/// We keep track for each pattern if it was ever useful during the analysis. This is used with
/// `redundant_subpatterns` to report redundant subpatterns arising from or patterns.
pub(crate) fn set_useful(&self) {
self.useful.set(true)
}
@ -132,19 +132,19 @@ impl<'p, Cx: MatchCx> DeconstructedPat<'p, Cx> {
}
}
/// Report the spans of subpatterns that were not useful, if any.
pub(crate) fn redundant_spans(&self) -> Vec<Cx::Span> {
let mut spans = Vec::new();
self.collect_redundant_spans(&mut spans);
spans
/// Report the subpatterns that were not useful, if any.
pub(crate) fn redundant_subpatterns(&self) -> Vec<&Self> {
let mut subpats = Vec::new();
self.collect_redundant_subpatterns(&mut subpats);
subpats
}
fn collect_redundant_spans(&self, spans: &mut Vec<Cx::Span>) {
fn collect_redundant_subpatterns<'a>(&'a self, subpats: &mut Vec<&'a Self>) {
// We don't look at subpatterns if we already reported the whole pattern as redundant.
if !self.is_useful() {
spans.push(self.span.clone());
subpats.push(self);
} else {
for p in self.iter_fields() {
p.collect_redundant_spans(spans);
p.collect_redundant_subpatterns(subpats);
}
}
}

View file

@ -35,7 +35,7 @@ pub(crate) type PatCtxt<'a, 'p, 'tcx> =
crate::usefulness::PatCtxt<'a, 'p, RustcMatchCheckCtxt<'p, 'tcx>>;
pub(crate) type SplitConstructorSet<'p, 'tcx> =
crate::constructor::SplitConstructorSet<RustcMatchCheckCtxt<'p, 'tcx>>;
pub type Usefulness = crate::usefulness::Usefulness<Span>;
pub type Usefulness<'p, 'tcx> = crate::usefulness::Usefulness<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
pub type UsefulnessReport<'p, 'tcx> =
crate::usefulness::UsefulnessReport<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
pub type WitnessPat<'p, 'tcx> = crate::pat::WitnessPat<RustcMatchCheckCtxt<'p, 'tcx>>;
@ -864,10 +864,10 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
impl<'p, 'tcx> MatchCx for RustcMatchCheckCtxt<'p, 'tcx> {
type Ty = Ty<'tcx>;
type Span = Span;
type VariantIdx = VariantIdx;
type StrLit = Const<'tcx>;
type ArmData = HirId;
type PatData = Span;
fn is_exhaustive_patterns_feature_on(&self) -> bool {
self.tcx.features().exhaustive_patterns

View file

@ -849,7 +849,7 @@ impl<'a, 'p, Cx: MatchCx> Matrix<'a, 'p, Cx> {
scrut_validity: ValidityConstraint,
) -> Self {
let wild_pattern =
wildcard_arena.alloc(DeconstructedPat::wildcard(scrut_ty, Cx::Span::default()));
wildcard_arena.alloc(DeconstructedPat::wildcard(scrut_ty, Default::default()));
let wildcard_row = PatStack::from_pattern(wild_pattern);
let mut matrix = Matrix {
rows: Vec::with_capacity(arms.len()),
@ -1287,11 +1287,11 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: MatchCx>(
/// Indicates whether or not a given arm is useful.
#[derive(Clone, Debug)]
pub enum Usefulness<Span> {
pub enum Usefulness<'p, Cx: MatchCx> {
/// The arm is useful. This additionally carries a set of or-pattern branches that have been
/// found to be redundant despite the overall arm being useful. Used only in the presence of
/// or-patterns, otherwise it stays empty.
Useful(Vec<Span>),
Useful(Vec<&'p DeconstructedPat<'p, Cx>>),
/// The arm is redundant and can be removed without changing the behavior of the match
/// expression.
Redundant,
@ -1300,7 +1300,7 @@ pub enum Usefulness<Span> {
/// The output of checking a match for exhaustiveness and arm usefulness.
pub struct UsefulnessReport<'p, Cx: MatchCx> {
/// For each arm of the input, whether that arm is useful after the arms above it.
pub arm_usefulness: Vec<(MatchArm<'p, Cx>, Usefulness<Cx::Span>)>,
pub arm_usefulness: Vec<(MatchArm<'p, Cx>, Usefulness<'p, Cx>)>,
/// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of
/// exhaustiveness.
pub non_exhaustiveness_witnesses: Vec<WitnessPat<Cx>>,
@ -1327,7 +1327,7 @@ pub fn compute_match_usefulness<'p, Cx: MatchCx>(
debug!(?arm);
// We warn when a pattern is not useful.
let usefulness = if arm.pat.is_useful() {
Usefulness::Useful(arm.pat.redundant_spans())
Usefulness::Useful(arm.pat.redundant_subpatterns())
} else {
Usefulness::Redundant
};