1
Fork 0

Abstract MatchCheckCtxt into a trait

This commit is contained in:
Nadrieril 2023-12-11 20:01:02 +01:00
parent 3ad76f9325
commit 3d7c4df326
8 changed files with 313 additions and 239 deletions

View file

@ -6,14 +6,12 @@ use std::fmt;
use smallvec::{smallvec, SmallVec};
use rustc_data_structures::captures::Captures;
use rustc_middle::ty::Ty;
use rustc_span::Span;
use self::Constructor::*;
use crate::constructor::{Constructor, Slice, SliceKind};
use crate::cx::MatchCheckCtxt;
use crate::usefulness::PatCtxt;
use crate::MatchCx;
/// Values and patterns can be represented as a constructor applied to some fields. This represents
/// a pattern in this form.
@ -26,25 +24,25 @@ use crate::usefulness::PatCtxt;
/// This happens if a private or `non_exhaustive` field is uninhabited, because the code mustn't
/// observe that it is uninhabited. In that case that field is not included in `fields`. Care must
/// be taken when converting to/from `thir::Pat`.
pub struct DeconstructedPat<'p, 'tcx> {
ctor: Constructor<'tcx>,
fields: &'p [DeconstructedPat<'p, 'tcx>],
ty: Ty<'tcx>,
span: Span,
pub struct DeconstructedPat<'p, Cx: MatchCx> {
ctor: Constructor<Cx>,
fields: &'p [DeconstructedPat<'p, Cx>],
ty: Cx::Ty,
span: Cx::Span,
/// Whether removing this arm would change the behavior of the match expression.
useful: Cell<bool>,
}
impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
pub fn wildcard(ty: Ty<'tcx>, span: Span) -> Self {
impl<'p, Cx: MatchCx> DeconstructedPat<'p, Cx> {
pub fn wildcard(ty: Cx::Ty, span: Cx::Span) -> Self {
Self::new(Wildcard, &[], ty, span)
}
pub fn new(
ctor: Constructor<'tcx>,
fields: &'p [DeconstructedPat<'p, 'tcx>],
ty: Ty<'tcx>,
span: Span,
ctor: Constructor<Cx>,
fields: &'p [DeconstructedPat<'p, Cx>],
ty: Cx::Ty,
span: Cx::Span,
) -> Self {
DeconstructedPat { ctor, fields, ty, span, useful: Cell::new(false) }
}
@ -61,19 +59,19 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
}
}
pub fn ctor(&self) -> &Constructor<'tcx> {
pub fn ctor(&self) -> &Constructor<Cx> {
&self.ctor
}
pub fn ty(&self) -> Ty<'tcx> {
pub fn ty(&self) -> Cx::Ty {
self.ty
}
pub fn span(&self) -> Span {
self.span
pub fn span(&self) -> &Cx::Span {
&self.span
}
pub fn iter_fields<'a>(
&'a self,
) -> impl Iterator<Item = &'p DeconstructedPat<'p, 'tcx>> + Captures<'a> {
) -> impl Iterator<Item = &'p DeconstructedPat<'p, Cx>> + Captures<'a> {
self.fields.iter()
}
@ -81,13 +79,13 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
/// `other_ctor` can be different from `self.ctor`, but must be covered by it.
pub(crate) fn specialize<'a>(
&self,
pcx: &PatCtxt<'a, 'p, 'tcx>,
other_ctor: &Constructor<'tcx>,
) -> SmallVec<[&'a DeconstructedPat<'p, 'tcx>; 2]> {
pcx: &PatCtxt<'a, 'p, Cx>,
other_ctor: &Constructor<Cx>,
) -> SmallVec<[&'a DeconstructedPat<'p, Cx>; 2]> {
let wildcard_sub_tys = || {
let tys = pcx.cx.ctor_sub_tys(other_ctor, pcx.ty);
tys.iter()
.map(|ty| DeconstructedPat::wildcard(*ty, Span::default()))
.map(|ty| DeconstructedPat::wildcard(*ty, Cx::Span::default()))
.map(|pat| pcx.wildcard_arena.alloc(pat) as &_)
.collect()
};
@ -137,15 +135,15 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
}
/// Report the spans of subpatterns that were not useful, if any.
pub(crate) fn redundant_spans(&self) -> Vec<Span> {
pub(crate) fn redundant_spans(&self) -> Vec<Cx::Span> {
let mut spans = Vec::new();
self.collect_redundant_spans(&mut spans);
spans
}
fn collect_redundant_spans(&self, spans: &mut Vec<Span>) {
fn collect_redundant_spans(&self, spans: &mut Vec<Cx::Span>) {
// We don't look at subpatterns if we already reported the whole pattern as redundant.
if !self.is_useful() {
spans.push(self.span);
spans.push(self.span.clone());
} else {
for p in self.iter_fields() {
p.collect_redundant_spans(spans);
@ -156,46 +154,46 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
/// This is mostly copied from the `Pat` impl. This is best effort and not good enough for a
/// `Display` impl.
impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
impl<'p, Cx: MatchCx> fmt::Debug for DeconstructedPat<'p, Cx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
MatchCheckCtxt::debug_pat(f, self)
Cx::debug_pat(f, self)
}
}
/// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics
/// purposes. As such they don't use interning and can be cloned.
#[derive(Debug, Clone)]
pub struct WitnessPat<'tcx> {
ctor: Constructor<'tcx>,
pub(crate) fields: Vec<WitnessPat<'tcx>>,
ty: Ty<'tcx>,
pub struct WitnessPat<Cx: MatchCx> {
ctor: Constructor<Cx>,
pub(crate) fields: Vec<WitnessPat<Cx>>,
ty: Cx::Ty,
}
impl<'tcx> WitnessPat<'tcx> {
pub(crate) fn new(ctor: Constructor<'tcx>, fields: Vec<Self>, ty: Ty<'tcx>) -> Self {
impl<Cx: MatchCx> WitnessPat<Cx> {
pub(crate) fn new(ctor: Constructor<Cx>, fields: Vec<Self>, ty: Cx::Ty) -> Self {
Self { ctor, fields, ty }
}
pub(crate) fn wildcard(ty: Ty<'tcx>) -> Self {
pub(crate) fn wildcard(ty: Cx::Ty) -> Self {
Self::new(Wildcard, Vec::new(), ty)
}
/// Construct a pattern that matches everything that starts with this constructor.
/// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
/// `Some(_)`.
pub(crate) fn wild_from_ctor(pcx: &PatCtxt<'_, '_, 'tcx>, ctor: Constructor<'tcx>) -> Self {
pub(crate) fn wild_from_ctor(pcx: &PatCtxt<'_, '_, Cx>, ctor: Constructor<Cx>) -> Self {
let field_tys = pcx.cx.ctor_sub_tys(&ctor, pcx.ty);
let fields = field_tys.iter().map(|ty| Self::wildcard(*ty)).collect();
Self::new(ctor, fields, pcx.ty)
}
pub fn ctor(&self) -> &Constructor<'tcx> {
pub fn ctor(&self) -> &Constructor<Cx> {
&self.ctor
}
pub fn ty(&self) -> Ty<'tcx> {
pub fn ty(&self) -> Cx::Ty {
self.ty
}
pub fn iter_fields<'a>(&'a self) -> impl Iterator<Item = &'a WitnessPat<'tcx>> {
pub fn iter_fields<'a>(&'a self) -> impl Iterator<Item = &'a WitnessPat<Cx>> {
self.fields.iter()
}
}