pattern_analysis
doesn't need to know what spans are
This commit is contained in:
parent
8c5e89907c
commit
1e89a38423
6 changed files with 39 additions and 36 deletions
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue