1use std::fmt;
8
9use fe_parser::{
10 ast::{LiteralPattern, MatchArm, Pattern},
11 node::Node,
12};
13use indexmap::{IndexMap, IndexSet};
14use smol_str::SmolStr;
15
16use crate::{
17 context::{AnalyzerContext, NamedThing},
18 display::{DisplayWithDb, Displayable},
19 namespace::{
20 items::{EnumVariantId, EnumVariantKind, Item, StructId, TypeDef},
21 scopes::BlockScope,
22 types::{Base, Type, TypeId},
23 },
24 AnalyzerDb,
25};
26
27#[derive(Clone, Debug, PartialEq, Eq)]
28pub struct PatternMatrix {
29 rows: Vec<PatternRowVec>,
30}
31
32impl PatternMatrix {
33 pub fn new(rows: Vec<PatternRowVec>) -> Self {
34 Self { rows }
35 }
36
37 pub fn from_arms<'db>(
38 scope: &'db BlockScope<'db, 'db>,
39 arms: &[Node<MatchArm>],
40 ty: TypeId,
41 ) -> Self {
42 let mut rows = Vec::with_capacity(arms.len());
43 for (i, arm) in arms.iter().enumerate() {
44 rows.push(PatternRowVec::new(vec![simplify_pattern(
45 scope,
46 &arm.kind.pat.kind,
47 ty,
48 i,
49 )]));
50 }
51
52 Self { rows }
53 }
54
55 pub fn rows(&self) -> &[PatternRowVec] {
56 &self.rows
57 }
58
59 pub fn into_rows(self) -> Vec<PatternRowVec> {
60 self.rows
61 }
62
63 pub fn find_non_exhaustiveness(&self, db: &dyn AnalyzerDb) -> Option<Vec<SimplifiedPattern>> {
64 if self.nrows() == 0 {
65 return Some(vec![]);
67 }
68 if self.ncols() == 0 {
69 return None;
70 }
71
72 let ty = self.first_column_ty();
73 let sigma_set = self.sigma_set();
74 if sigma_set.is_complete(db) {
75 for ctor in sigma_set.into_iter() {
76 match self.phi_specialize(db, ctor).find_non_exhaustiveness(db) {
77 Some(vec) if vec.is_empty() => {
78 let pat_kind = SimplifiedPatternKind::Constructor {
79 kind: ctor,
80 fields: vec![],
81 };
82 let pat = SimplifiedPattern::new(pat_kind, ty);
83
84 return Some(vec![pat]);
85 }
86
87 Some(mut vec) => {
88 let field_num = ctor.arity(db);
89 debug_assert!(vec.len() >= field_num);
90 let rem = vec.split_off(field_num);
91 let pat_kind = SimplifiedPatternKind::Constructor {
92 kind: ctor,
93 fields: vec,
94 };
95 let pat = SimplifiedPattern::new(pat_kind, ty);
96
97 let mut result = vec![pat];
98 result.extend_from_slice(&rem);
99 return Some(result);
100 }
101
102 None => {}
103 }
104 }
105
106 None
107 } else {
108 self.d_specialize(db)
109 .find_non_exhaustiveness(db)
110 .map(|vec| {
111 let sigma_set = self.sigma_set();
112 let kind = if sigma_set.is_empty() {
113 SimplifiedPatternKind::WildCard(None)
114 } else {
115 let complete_sigma = SigmaSet::complete_sigma(db, ty);
116 SimplifiedPatternKind::Or(
117 complete_sigma
118 .difference(&sigma_set)
119 .into_iter()
120 .map(|ctor| {
121 let kind =
122 SimplifiedPatternKind::ctor_with_wild_card_fields(db, ctor);
123 SimplifiedPattern::new(kind, ty)
124 })
125 .collect(),
126 )
127 };
128
129 let mut result = vec![SimplifiedPattern::new(kind, ty)];
130 result.extend_from_slice(&vec);
131
132 result
133 })
134 }
135 }
136
137 pub fn is_row_useful(&self, db: &dyn AnalyzerDb, row: usize) -> bool {
138 debug_assert!(self.nrows() > row);
139
140 Self {
141 rows: self.rows[0..row].to_vec(),
142 }
143 .is_pattern_useful(db, &self.rows[row])
144 }
145
146 pub fn nrows(&self) -> usize {
147 self.rows.len()
148 }
149
150 pub fn ncols(&self) -> usize {
151 debug_assert_ne!(self.nrows(), 0);
152 let ncols = self.rows[0].len();
153 debug_assert!(self.rows.iter().all(|row| row.len() == ncols));
154 ncols
155 }
156
157 pub fn swap_col(&mut self, col1: usize, col2: usize) {
158 for row in &mut self.rows {
159 row.swap(col1, col2);
160 }
161 }
162
163 pub fn sigma_set(&self) -> SigmaSet {
164 SigmaSet::from_rows(self.rows.iter(), 0)
165 }
166
167 pub fn phi_specialize(&self, db: &dyn AnalyzerDb, ctor: ConstructorKind) -> Self {
168 let mut new_cols = Vec::new();
169 for col in &self.rows {
170 new_cols.extend_from_slice(&col.phi_specialize(db, ctor));
171 }
172 Self { rows: new_cols }
173 }
174
175 pub fn d_specialize(&self, db: &dyn AnalyzerDb) -> Self {
176 let mut new_cols = Vec::new();
177 for col in &self.rows {
178 new_cols.extend_from_slice(&col.d_specialize(db));
179 }
180 Self { rows: new_cols }
181 }
182
183 fn first_column_ty(&self) -> TypeId {
184 debug_assert_ne!(self.ncols(), 0);
185 self.rows[0].first_column_ty()
186 }
187
188 fn is_pattern_useful(&self, db: &dyn AnalyzerDb, pat_vec: &PatternRowVec) -> bool {
189 if self.nrows() == 0 {
190 return true;
191 }
192
193 if self.ncols() == 0 {
194 return false;
195 }
196
197 match &pat_vec.head().unwrap().kind {
198 SimplifiedPatternKind::WildCard(_) => self
199 .d_specialize(db)
200 .is_pattern_useful(db, &pat_vec.d_specialize(db)[0]),
201
202 SimplifiedPatternKind::Constructor { kind, .. } => self
203 .phi_specialize(db, *kind)
204 .is_pattern_useful(db, &pat_vec.phi_specialize(db, *kind)[0]),
205
206 SimplifiedPatternKind::Or(pats) => {
207 for pat in pats {
208 if self.is_pattern_useful(db, &PatternRowVec::new(vec![pat.clone()])) {
209 return true;
210 }
211 }
212 false
213 }
214 }
215 }
216}
217
218#[derive(Clone, Debug, PartialEq, Eq)]
219pub struct SimplifiedPattern {
220 pub kind: SimplifiedPatternKind,
221 pub ty: TypeId,
222}
223
224impl SimplifiedPattern {
225 pub fn new(kind: SimplifiedPatternKind, ty: TypeId) -> Self {
226 Self { kind, ty }
227 }
228
229 pub fn wildcard(bind: Option<(SmolStr, usize)>, ty: TypeId) -> Self {
230 Self::new(SimplifiedPatternKind::WildCard(bind), ty)
231 }
232
233 pub fn is_wildcard(&self) -> bool {
234 matches!(self.kind, SimplifiedPatternKind::WildCard(_))
235 }
236}
237
238impl DisplayWithDb for SimplifiedPattern {
239 fn format(&self, db: &dyn AnalyzerDb, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240 match &self.kind {
241 SimplifiedPatternKind::WildCard(None) => write!(f, "_"),
242 SimplifiedPatternKind::WildCard(Some((name, _))) => write!(f, "{name}"),
243
244 SimplifiedPatternKind::Constructor {
245 kind: ConstructorKind::Enum(id),
246 fields,
247 } => {
248 let ctor_name = id.name_with_parent(db);
249 write!(f, "{ctor_name}")?;
250 if !id.kind(db).unwrap().is_unit() {
251 write!(f, "(")?;
252 let mut delim = "";
253 for field in fields {
254 let displayable = field.display(db);
255 write!(f, "{delim}{displayable}")?;
256 delim = ", ";
257 }
258 write!(f, ")")
259 } else {
260 Ok(())
261 }
262 }
263
264 SimplifiedPatternKind::Constructor {
265 kind: ConstructorKind::Tuple(_),
266 fields,
267 } => {
268 write!(f, "(")?;
269 let mut delim = "";
270 for field in fields {
271 let displayable = field.display(db);
272 write!(f, "{delim}{displayable}")?;
273 delim = ", ";
274 }
275 write!(f, ")")
276 }
277
278 SimplifiedPatternKind::Constructor {
279 kind: ConstructorKind::Struct(sid),
280 fields,
281 } => {
282 let struct_name = sid.name(db);
283 write!(f, "{struct_name} {{ ")?;
284 let mut delim = "";
285
286 for (field_name, field_pat) in sid
287 .fields(db)
288 .iter()
289 .map(|(field_name, _)| field_name)
290 .zip(fields.iter())
291 {
292 let displayable = field_pat.display(db);
293 write!(f, "{delim}{field_name}: {displayable}")?;
294 delim = ", ";
295 }
296 write!(f, "}}")
297 }
298
299 SimplifiedPatternKind::Constructor {
300 kind: ConstructorKind::Literal((lit, _)),
301 ..
302 } => {
303 write!(f, "{lit}")
304 }
305
306 SimplifiedPatternKind::Or(pats) => {
307 let mut delim = "";
308 for pat in pats {
309 let pat = pat.display(db);
310 write!(f, "{delim}{pat}")?;
311 delim = " | ";
312 }
313 Ok(())
314 }
315 }
316 }
317}
318
319#[derive(Clone, Debug, PartialEq, Eq)]
320pub enum SimplifiedPatternKind {
321 WildCard(Option<(SmolStr, usize)>),
322 Constructor {
323 kind: ConstructorKind,
324 fields: Vec<SimplifiedPattern>,
325 },
326 Or(Vec<SimplifiedPattern>),
327}
328
329impl SimplifiedPatternKind {
330 pub fn collect_ctors(&self) -> Vec<ConstructorKind> {
331 match self {
332 Self::WildCard(_) => vec![],
333 Self::Constructor { kind, .. } => vec![*kind],
334 Self::Or(pats) => {
335 let mut ctors = vec![];
336 for pat in pats {
337 ctors.extend_from_slice(&pat.kind.collect_ctors());
338 }
339 ctors
340 }
341 }
342 }
343
344 pub fn ctor_with_wild_card_fields(db: &dyn AnalyzerDb, kind: ConstructorKind) -> Self {
345 let fields = kind
346 .field_types(db)
347 .into_iter()
348 .map(|ty| SimplifiedPattern::wildcard(None, ty))
349 .collect();
350 Self::Constructor { kind, fields }
351 }
352}
353
354#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
355pub enum ConstructorKind {
356 Enum(EnumVariantId),
357 Tuple(TypeId),
358 Struct(StructId),
359 Literal((LiteralPattern, TypeId)),
360}
361
362#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
363pub enum LiteralConstructor {
364 Bool(bool),
365}
366
367impl ConstructorKind {
368 pub fn field_types(&self, db: &dyn AnalyzerDb) -> Vec<TypeId> {
369 match self {
370 Self::Enum(id) => match id.kind(db).unwrap() {
371 EnumVariantKind::Unit => vec![],
372 EnumVariantKind::Tuple(types) => types.to_vec(),
373 },
374 Self::Tuple(ty) => ty.tuple_elts(db),
375 Self::Struct(sid) => sid
376 .fields(db)
377 .iter()
378 .map(|(_, fid)| fid.typ(db).unwrap())
379 .collect(),
380 Self::Literal(_) => vec![],
381 }
382 }
383
384 pub fn arity(&self, db: &dyn AnalyzerDb) -> usize {
385 match self {
386 Self::Enum(id) => match id.kind(db).unwrap() {
387 EnumVariantKind::Unit => 0,
388 EnumVariantKind::Tuple(types) => types.len(),
389 },
390 Self::Tuple(ty) => ty.tuple_elts(db).len(),
391 Self::Struct(sid) => sid.fields(db).len(),
392 Self::Literal(_) => 0,
393 }
394 }
395
396 pub fn ty(&self, db: &dyn AnalyzerDb) -> TypeId {
397 match self {
398 Self::Enum(id) => id.parent(db).as_type(db),
399 Self::Tuple(ty) => *ty,
400 Self::Struct(sid) => sid.as_type(db),
401 Self::Literal((_, ty)) => *ty,
402 }
403 }
404}
405
406#[derive(Clone, Debug, PartialEq, Eq)]
407pub struct SigmaSet(IndexSet<ConstructorKind>);
408
409impl SigmaSet {
410 pub fn from_rows<'a>(rows: impl Iterator<Item = &'a PatternRowVec>, column: usize) -> Self {
411 let mut ctor_set = IndexSet::new();
412 for row in rows {
413 for ctor in row.collect_column_ctors(column) {
414 ctor_set.insert(ctor);
415 }
416 }
417 Self(ctor_set)
418 }
419
420 pub fn complete_sigma(db: &dyn AnalyzerDb, ty: TypeId) -> Self {
421 let inner = match ty.typ(db) {
422 Type::Enum(id) => id
423 .variants(db)
424 .values()
425 .map(|id| ConstructorKind::Enum(*id))
426 .collect(),
427
428 Type::Tuple(_) => [ConstructorKind::Tuple(ty)].into_iter().collect(),
429
430 Type::Base(Base::Bool) => [
431 ConstructorKind::Literal((LiteralPattern::Bool(true), ty)),
432 ConstructorKind::Literal((LiteralPattern::Bool(false), ty)),
433 ]
434 .into_iter()
435 .collect(),
436
437 _ => {
438 unimplemented!()
439 }
440 };
441
442 Self(inner)
443 }
444
445 pub fn is_complete(&self, db: &dyn AnalyzerDb) -> bool {
446 match self.0.first() {
447 Some(ctor) => {
448 let expected = ctor_variant_num(db, *ctor);
449 debug_assert!(self.len() <= expected);
450 self.len() == expected
451 }
452 None => false,
453 }
454 }
455
456 pub fn len(&self) -> usize {
457 self.0.len()
458 }
459
460 pub fn is_empty(&self) -> bool {
461 self.0.is_empty()
462 }
463
464 pub fn iter(&self) -> impl Iterator<Item = &ConstructorKind> {
465 self.0.iter()
466 }
467
468 pub fn difference(&self, other: &Self) -> Self {
469 Self(self.0.difference(&other.0).cloned().collect())
470 }
471}
472
473impl IntoIterator for SigmaSet {
474 type Item = ConstructorKind;
475 type IntoIter = <IndexSet<ConstructorKind> as IntoIterator>::IntoIter;
476
477 fn into_iter(self) -> Self::IntoIter {
478 self.0.into_iter()
479 }
480}
481
482#[derive(Clone, Debug, PartialEq, Eq)]
483pub struct PatternRowVec {
484 pub inner: Vec<SimplifiedPattern>,
485}
486
487impl PatternRowVec {
488 pub fn new(inner: Vec<SimplifiedPattern>) -> Self {
489 Self { inner }
490 }
491
492 pub fn len(&self) -> usize {
493 self.inner.len()
494 }
495
496 pub fn is_empty(&self) -> bool {
497 self.inner.is_empty()
498 }
499
500 pub fn pats(&self) -> &[SimplifiedPattern] {
501 &self.inner
502 }
503
504 pub fn head(&self) -> Option<&SimplifiedPattern> {
505 self.inner.first()
506 }
507
508 pub fn phi_specialize(&self, db: &dyn AnalyzerDb, ctor: ConstructorKind) -> Vec<Self> {
509 debug_assert!(!self.inner.is_empty());
510
511 let first_pat = &self.inner[0];
512 let ctor_fields = ctor.field_types(db);
513 match &first_pat.kind {
514 SimplifiedPatternKind::WildCard(bind) => {
515 let mut inner = Vec::with_capacity(self.inner.len() + ctor_fields.len() - 1);
516 for field_ty in ctor_fields {
517 inner.push(SimplifiedPattern::wildcard(bind.clone(), field_ty));
518 }
519 inner.extend_from_slice(&self.inner[1..]);
520 vec![Self::new(inner)]
521 }
522
523 SimplifiedPatternKind::Constructor { kind, fields } => {
524 if *kind == ctor {
525 let mut inner = Vec::with_capacity(self.inner.len() + ctor_fields.len() - 1);
526 inner.extend_from_slice(fields);
527 inner.extend_from_slice(&self.inner[1..]);
528 vec![Self::new(inner)]
529 } else {
530 vec![]
531 }
532 }
533
534 SimplifiedPatternKind::Or(pats) => {
535 let mut result = vec![];
536 for pat in pats {
537 let mut tmp_inner = Vec::with_capacity(self.inner.len());
538 tmp_inner.push(pat.clone());
539 tmp_inner.extend_from_slice(&self.inner[1..]);
540 let tmp = PatternRowVec::new(tmp_inner);
541 for v in tmp.phi_specialize(db, ctor) {
542 result.push(v);
543 }
544 }
545 result
546 }
547 }
548 }
549
550 pub fn swap(&mut self, a: usize, b: usize) {
551 self.inner.swap(a, b);
552 }
553
554 pub fn d_specialize(&self, _db: &dyn AnalyzerDb) -> Vec<Self> {
555 debug_assert!(!self.inner.is_empty());
556
557 let first_pat = &self.inner[0];
558 match &first_pat.kind {
559 SimplifiedPatternKind::WildCard(_) => {
560 let inner = self.inner[1..].to_vec();
561 vec![Self::new(inner)]
562 }
563
564 SimplifiedPatternKind::Constructor { .. } => {
565 vec![]
566 }
567
568 SimplifiedPatternKind::Or(pats) => {
569 let mut result = vec![];
570 for pat in pats {
571 let mut tmp_inner = Vec::with_capacity(self.inner.len());
572 tmp_inner.push(pat.clone());
573 tmp_inner.extend_from_slice(&self.inner[1..]);
574 let tmp = PatternRowVec::new(tmp_inner);
575 for v in tmp.d_specialize(_db) {
576 result.push(v);
577 }
578 }
579 result
580 }
581 }
582 }
583
584 pub fn collect_column_ctors(&self, column: usize) -> Vec<ConstructorKind> {
585 debug_assert!(!self.inner.is_empty());
586
587 let first_pat = &self.inner[column];
588 first_pat.kind.collect_ctors()
589 }
590
591 fn first_column_ty(&self) -> TypeId {
592 debug_assert!(!self.inner.is_empty());
593
594 self.inner[0].ty
595 }
596}
597
598fn ctor_variant_num(db: &dyn AnalyzerDb, ctor: ConstructorKind) -> usize {
599 match ctor {
600 ConstructorKind::Enum(variant) => {
601 let enum_id = variant.parent(db);
602 enum_id.variants(db).len()
603 }
604 ConstructorKind::Tuple(_) | ConstructorKind::Struct(_) => 1,
605 ConstructorKind::Literal((LiteralPattern::Bool(_), _)) => 2,
606 }
607}
608
609fn simplify_pattern(
610 scope: &BlockScope,
611 pat: &Pattern,
612 ty: TypeId,
613 arm_idx: usize,
614) -> SimplifiedPattern {
615 let kind = match pat {
616 Pattern::WildCard => SimplifiedPatternKind::WildCard(None),
617
618 Pattern::Rest => {
619 unreachable!()
621 }
622
623 Pattern::Literal(lit) => {
624 let ctor_kind = ConstructorKind::Literal((lit.kind, ty));
625 SimplifiedPatternKind::Constructor {
626 kind: ctor_kind,
627 fields: vec![],
628 }
629 }
630
631 Pattern::Tuple(elts) => {
632 let ctor_kind = ConstructorKind::Tuple(ty);
633 let elts_tys = ty.tuple_elts(scope.db());
634
635 SimplifiedPatternKind::Constructor {
636 kind: ctor_kind,
637 fields: simplify_tuple_pattern(scope, elts, &elts_tys, arm_idx),
638 }
639 }
640
641 Pattern::Path(path) => match scope.resolve_visible_path(&path.kind) {
642 Some(NamedThing::EnumVariant(variant)) => SimplifiedPatternKind::Constructor {
643 kind: ConstructorKind::Enum(variant),
644 fields: vec![],
645 },
646 _ => {
647 debug_assert!(path.kind.segments.len() == 1);
648 SimplifiedPatternKind::WildCard(Some((path.kind.segments[0].kind.clone(), arm_idx)))
649 }
650 },
651
652 Pattern::PathTuple(path, elts) => {
653 let variant = match scope.resolve_visible_path(&path.kind).unwrap() {
654 NamedThing::EnumVariant(variant) => variant,
655 _ => unreachable!(),
656 };
657 let ctor_kind = ConstructorKind::Enum(variant);
658 let elts_tys = ctor_kind.field_types(scope.db());
659
660 SimplifiedPatternKind::Constructor {
661 kind: ctor_kind,
662 fields: simplify_tuple_pattern(scope, elts, &elts_tys, arm_idx),
663 }
664 }
665
666 Pattern::PathStruct {
667 path,
668 fields: pat_fields,
669 ..
670 } => {
671 let (sid, ctor_kind) = match scope.resolve_visible_path(&path.kind).unwrap() {
672 NamedThing::Item(Item::Type(TypeDef::Struct(sid))) => {
673 (sid, ConstructorKind::Struct(sid))
674 }
675 NamedThing::EnumVariant(_) => todo!(),
677 _ => unreachable!(),
678 };
679
680 let pat_fields: IndexMap<_, _> = pat_fields
683 .iter()
684 .map(|field_pat| (field_pat.0.kind.clone(), field_pat.1.clone()))
685 .collect();
686 let fields_def = sid.fields(scope.db());
687 let mut canonicalized_fields = Vec::with_capacity(fields_def.len());
688 for (field_name, fid) in fields_def.iter() {
689 let field_ty = fid.typ(scope.db()).unwrap();
690 if let Some(pat) = pat_fields.get(field_name) {
691 let pat = simplify_pattern(scope, &pat.kind, field_ty, arm_idx);
692 canonicalized_fields.push(pat);
693 } else {
694 canonicalized_fields.push(SimplifiedPattern::wildcard(None, field_ty));
695 }
696 }
697
698 SimplifiedPatternKind::Constructor {
699 kind: ctor_kind,
700 fields: canonicalized_fields,
701 }
702 }
703
704 Pattern::Or(pats) => SimplifiedPatternKind::Or(
705 pats.iter()
706 .map(|pat| simplify_pattern(scope, &pat.kind, ty, arm_idx))
707 .collect(),
708 ),
709 };
710
711 SimplifiedPattern::new(kind, ty)
712}
713
714fn simplify_tuple_pattern(
715 scope: &BlockScope,
716 elts: &[Node<Pattern>],
717 elts_tys: &[TypeId],
718 arm_idx: usize,
719) -> Vec<SimplifiedPattern> {
720 let mut simplified_elts = vec![];
721 let mut tys_iter = elts_tys.iter();
722
723 for pat in elts {
724 if pat.kind.is_rest() {
725 for _ in 0..(elts_tys.len() - (elts.len() - 1)) {
726 let ty = tys_iter.next().unwrap();
727 simplified_elts.push(SimplifiedPattern::new(
728 SimplifiedPatternKind::WildCard(None),
729 *ty,
730 ));
731 }
732 } else {
733 simplified_elts.push(simplify_pattern(
734 scope,
735 &pat.kind,
736 *tys_iter.next().unwrap(),
737 arm_idx,
738 ));
739 }
740 }
741
742 debug_assert!(tys_iter.next().is_none());
743 simplified_elts
744}
745
746impl TypeId {
747 fn tuple_elts(self, db: &dyn AnalyzerDb) -> Vec<TypeId> {
748 match self.typ(db) {
749 Type::Tuple(tup) => tup.items.to_vec(),
750 _ => unreachable!(),
751 }
752 }
753}