use crate::constructor::{Constructor, SplitConstructorSet};
use crate::pat::{DeconstructedPat, PatOrWild};
use crate::{MatchArm, PatCx};
#[derive(Debug)]
pub struct PatternColumn<'p, Cx: PatCx> {
patterns: Vec<&'p DeconstructedPat<Cx>>,
}
impl<'p, Cx: PatCx> PatternColumn<'p, Cx> {
pub fn new(arms: &[MatchArm<'p, Cx>]) -> Self {
let patterns = Vec::with_capacity(arms.len());
let mut column = PatternColumn { patterns };
for arm in arms {
column.expand_and_push(PatOrWild::Pat(arm.pat));
}
column
}
fn expand_and_push(&mut self, pat: PatOrWild<'p, Cx>) {
if pat.is_or_pat() {
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)
}
}
pub fn head_ty(&self) -> Option<&Cx::Ty> {
self.patterns.first().map(|pat| pat.ty())
}
pub fn iter(&self) -> impl Iterator<Item = &'p DeconstructedPat<Cx>> {
self.patterns.iter().copied()
}
pub fn analyze_ctors(
&self,
cx: &Cx,
ty: &Cx::Ty,
) -> Result<SplitConstructorSet<Cx>, Cx::Error> {
let column_ctors = self.patterns.iter().map(|p| p.ctor());
let ctors_for_ty = cx.ctors_for_ty(ty)?;
Ok(ctors_for_ty.split(column_ctors))
}
pub fn specialize(
&self,
cx: &Cx,
ty: &Cx::Ty,
ctor: &Constructor<Cx>,
) -> Vec<PatternColumn<'p, Cx>> {
let arity = ctor.arity(cx, ty);
if arity == 0 {
return Vec::new();
}
let mut specialized_columns: Vec<_> =
(0..arity).map(|_| Self { patterns: Vec::new() }).collect();
let relevant_patterns =
self.patterns.iter().filter(|pat| ctor.is_covered_by(cx, pat.ctor()).unwrap_or(false));
for pat in relevant_patterns {
let specialized = pat.specialize(ctor, arity);
for (subpat, column) in specialized.into_iter().zip(&mut specialized_columns) {
column.expand_and_push(subpat);
}
}
specialized_columns
}
}