diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs index de87875fd0edb..4fdbbfa85784a 100644 --- a/compiler/rustc_pattern_analysis/src/lints.rs +++ b/compiler/rustc_pattern_analysis/src/lints.rs @@ -11,6 +11,7 @@ use crate::errors::{ NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Overlap, OverlappingRangeEndpoints, Uncovered, }; +use crate::pat::PatOrWild; use crate::rustc::{ Constructor, DeconstructedPat, MatchArm, MatchCtxt, PlaceCtxt, RevealedTy, RustcMatchCheckCtxt, SplitConstructorSet, WitnessPat, @@ -36,21 +37,21 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> { let patterns = Vec::with_capacity(arms.len()); let mut column = PatternColumn { patterns }; for arm in arms { - column.expand_and_push(arm.pat); + column.expand_and_push(PatOrWild::Pat(arm.pat)); } column } - fn expand_and_push(&mut self, pat: &'p DeconstructedPat<'p, 'tcx>) { + fn expand_and_push(&mut self, pat: PatOrWild<'p, RustcMatchCheckCtxt<'p, 'tcx>>) { + // We flatten or-patterns and skip wildcards if pat.is_or_pat() { - self.patterns.extend(pat.flatten_or_pat()) - } else { + self.patterns.extend( + pat.flatten_or_pat().into_iter().filter_map(|pat_or_wild| pat_or_wild.as_pat()), + ) + } else if let Some(pat) = pat.as_pat() { self.patterns.push(pat) } } - fn is_empty(&self) -> bool { - self.patterns.is_empty() - } fn head_ty(&self) -> Option<RevealedTy<'tcx>> { self.patterns.first().map(|pat| pat.ty()) } @@ -90,7 +91,7 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> { let ctor_sub_tys = pcx.ctor_sub_tys(ctor); for pat in relevant_patterns { let specialized = pat.specialize(pcx, ctor, ctor_sub_tys); - for (subpat, column) in specialized.iter().zip(&mut specialized_columns) { + for (subpat, column) in specialized.into_iter().zip(&mut specialized_columns) { column.expand_and_push(subpat); } } diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs index 4438d20a3579b..f1594409d302b 100644 --- a/compiler/rustc_pattern_analysis/src/pat.rs +++ b/compiler/rustc_pattern_analysis/src/pat.rs @@ -10,6 +10,7 @@ use crate::usefulness::PlaceCtxt; use crate::{Captures, TypeCx}; use self::Constructor::*; +use self::PatOrWild::*; /// Values and patterns can be represented as a constructor applied to some fields. This represents /// a pattern in this form. @@ -50,14 +51,6 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { pub(crate) fn is_or_pat(&self) -> bool { matches!(self.ctor, Or) } - /// Expand this (possibly-nested) or-pattern into its alternatives. - pub(crate) fn flatten_or_pat(&self) -> SmallVec<[&Self; 1]> { - if self.is_or_pat() { - self.iter_fields().flat_map(|p| p.flatten_or_pat()).collect() - } else { - smallvec![self] - } - } pub fn ctor(&self) -> &Constructor<Cx> { &self.ctor @@ -79,17 +72,11 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { /// `other_ctor` can be different from `self.ctor`, but must be covered by it. pub(crate) fn specialize( &self, - pcx: &PlaceCtxt<'_, 'p, Cx>, + _pcx: &PlaceCtxt<'_, 'p, Cx>, other_ctor: &Constructor<Cx>, ctor_sub_tys: &[Cx::Ty], - ) -> SmallVec<[&'p DeconstructedPat<'p, Cx>; 2]> { - let wildcard_sub_tys = || { - ctor_sub_tys - .iter() - .map(|ty| DeconstructedPat::wildcard(*ty)) - .map(|pat| pcx.mcx.wildcard_arena.alloc(pat) as &_) - .collect() - }; + ) -> SmallVec<[PatOrWild<'p, Cx>; 2]> { + let wildcard_sub_tys = || ctor_sub_tys.iter().map(|_| Wild).collect(); match (&self.ctor, other_ctor) { // Return a wildcard for each field of `other_ctor`. (Wildcard, _) => wildcard_sub_tys(), @@ -105,14 +92,14 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { // Fill in the fields from both ends. let new_arity = fields.len(); for i in 0..prefix { - fields[i] = &self.fields[i]; + fields[i] = Pat(&self.fields[i]); } for i in 0..suffix { - fields[new_arity - 1 - i] = &self.fields[self.fields.len() - 1 - i]; + fields[new_arity - 1 - i] = Pat(&self.fields[self.fields.len() - 1 - i]); } fields } - _ => self.fields.iter().collect(), + _ => self.fields.iter().map(Pat).collect(), } } @@ -153,14 +140,84 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { } } -/// This is mostly copied from the `Pat` impl. This is best effort and not good enough for a -/// `Display` impl. +/// This is best effort and not good enough for a `Display` impl. impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Cx::debug_pat(f, self) } } +/// Represents either a pattern obtained from user input or a wildcard constructed during the +/// algorithm. Do not use `Wild` to represent a wildcard pattern comping from user input. +/// +/// This is morally `Option<&'p DeconstructedPat>` where `None` is interpreted as a wildcard. +#[derive(derivative::Derivative)] +#[derivative(Clone(bound = ""), Copy(bound = ""))] +pub(crate) enum PatOrWild<'p, Cx: TypeCx> { + /// A non-user-provided wildcard, created during specialization. + Wild, + /// A user-provided pattern. + Pat(&'p DeconstructedPat<'p, Cx>), +} + +impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> { + pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<'p, Cx>> { + match self { + Wild => None, + Pat(pat) => Some(pat), + } + } + pub(crate) fn ctor(self) -> &'p Constructor<Cx> { + match self { + Wild => &Wildcard, + Pat(pat) => pat.ctor(), + } + } + + pub(crate) fn is_or_pat(&self) -> bool { + matches!(self.ctor(), Or) + } + + /// Expand this (possibly-nested) or-pattern into its alternatives. + pub(crate) fn flatten_or_pat(self) -> SmallVec<[Self; 1]> { + match self { + Pat(pat) if pat.is_or_pat() => { + pat.iter_fields().flat_map(|p| Pat(p).flatten_or_pat()).collect() + } + _ => smallvec![self], + } + } + + /// Specialize this pattern with a constructor. + /// `other_ctor` can be different from `self.ctor`, but must be covered by it. + pub(crate) fn specialize( + &self, + pcx: &PlaceCtxt<'_, 'p, Cx>, + other_ctor: &Constructor<Cx>, + ctor_sub_tys: &[Cx::Ty], + ) -> SmallVec<[PatOrWild<'p, Cx>; 2]> { + match self { + Wild => ctor_sub_tys.iter().map(|_| Wild).collect(), + Pat(pat) => pat.specialize(pcx, other_ctor, ctor_sub_tys), + } + } + + pub(crate) fn set_useful(&self) { + if let Pat(pat) = self { + pat.set_useful() + } + } +} + +impl<'p, Cx: TypeCx> fmt::Debug for PatOrWild<'p, Cx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Wild => write!(f, "_"), + Pat(pat) => pat.fmt(f), + } + } +} + /// 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(derivative::Derivative)] diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 16bf709881b6b..517d68115b78e 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -716,7 +716,7 @@ use smallvec::{smallvec, SmallVec}; use std::fmt; use crate::constructor::{Constructor, ConstructorSet}; -use crate::pat::{DeconstructedPat, WitnessPat}; +use crate::pat::{DeconstructedPat, PatOrWild, WitnessPat}; use crate::{Captures, MatchArm, MatchCtxt, TypeCx}; use self::ValidityConstraint::*; @@ -827,7 +827,7 @@ impl fmt::Display for ValidityConstraint { #[derivative(Clone(bound = ""))] struct PatStack<'p, Cx: TypeCx> { // Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well. - pats: SmallVec<[&'p DeconstructedPat<'p, Cx>; 2]>, + pats: SmallVec<[PatOrWild<'p, Cx>; 2]>, /// Sometimes we know that as far as this row is concerned, the current case is already handled /// by a different, more general, case. When the case is irrelevant for all rows this allows us /// to skip a case entirely. This is purely an optimization. See at the top for details. @@ -836,7 +836,7 @@ struct PatStack<'p, Cx: TypeCx> { impl<'p, Cx: TypeCx> PatStack<'p, Cx> { fn from_pattern(pat: &'p DeconstructedPat<'p, Cx>) -> Self { - PatStack { pats: smallvec![pat], relevant: true } + PatStack { pats: smallvec![PatOrWild::Pat(pat)], relevant: true } } fn is_empty(&self) -> bool { @@ -847,14 +847,11 @@ impl<'p, Cx: TypeCx> PatStack<'p, Cx> { self.pats.len() } - fn head_opt(&self) -> Option<&'p DeconstructedPat<'p, Cx>> { - self.pats.first().copied() - } - fn head(&self) -> &'p DeconstructedPat<'p, Cx> { - self.head_opt().unwrap() + fn head(&self) -> PatOrWild<'p, Cx> { + self.pats[0] } - fn iter(&self) -> impl Iterator<Item = &'p DeconstructedPat<'p, Cx>> + Captures<'_> { + fn iter(&self) -> impl Iterator<Item = PatOrWild<'p, Cx>> + Captures<'_> { self.pats.iter().copied() } @@ -926,11 +923,11 @@ impl<'p, Cx: TypeCx> MatrixRow<'p, Cx> { self.pats.len() } - fn head(&self) -> &'p DeconstructedPat<'p, Cx> { + fn head(&self) -> PatOrWild<'p, Cx> { self.pats.head() } - fn iter(&self) -> impl Iterator<Item = &'p DeconstructedPat<'p, Cx>> + Captures<'_> { + fn iter(&self) -> impl Iterator<Item = PatOrWild<'p, Cx>> + Captures<'_> { self.pats.iter() } @@ -1054,7 +1051,7 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { } /// Iterate over the first pattern of each row. - fn heads(&self) -> impl Iterator<Item = &'p DeconstructedPat<'p, Cx>> + Clone + Captures<'_> { + fn heads(&self) -> impl Iterator<Item = PatOrWild<'p, Cx>> + Clone + Captures<'_> { self.rows().map(|r| r.head()) }