1use super::functions::*;
6use crate::context::ElabContext;
7use oxilean_kernel::{Environment, Expr, FVarId, Level, Name};
8use oxilean_parse::{Located, MatchArm, Pattern, SurfaceExpr};
9use std::collections::HashMap;
10
11#[derive(Debug, Clone)]
13#[allow(dead_code)]
14pub struct DecisionTree {
15 root: DecisionNode,
17}
18impl DecisionTree {
19 pub fn new(arms: &[(Located<Pattern>, Located<SurfaceExpr>)]) -> Result<Self, String> {
21 if arms.is_empty() {
22 return Ok(Self {
23 root: DecisionNode::Leaf(Expr::BVar(0)),
24 });
25 }
26 let mut node = DecisionNode::Fail;
27 for (pat, rhs_surf) in arms.iter().rev() {
28 let rhs = surface_to_placeholder(&rhs_surf.value);
29 node = build_node_from_pattern(&pat.value, rhs, node);
30 }
31 Ok(Self { root: node })
32 }
33 #[allow(dead_code)]
35 pub fn from_equations(equations: &[MatchEquation]) -> Result<Self, String> {
36 if equations.is_empty() {
37 return Ok(Self {
38 root: DecisionNode::Fail,
39 });
40 }
41 let mut node = DecisionNode::Fail;
42 for eq in equations.iter().rev() {
43 if eq.patterns.is_empty() {
44 node = DecisionNode::Leaf(eq.rhs.clone());
45 } else {
46 node = build_node_from_elab_pattern(&eq.patterns[0], eq.rhs.clone(), node);
47 }
48 }
49 Ok(Self { root: node })
50 }
51 pub fn compile(&self) -> Expr {
53 compile_node(&self.root)
54 }
55}
56#[allow(dead_code)]
58pub struct MatchElaborator {
59 next_var: u64,
61 pub check_exhaustive: bool,
63 pub check_redundant: bool,
65}
66#[allow(dead_code)]
67impl MatchElaborator {
68 pub fn new() -> Self {
70 Self {
71 next_var: 10000,
72 check_exhaustive: true,
73 check_redundant: true,
74 }
75 }
76 pub fn fresh_fvar(&mut self) -> FVarId {
78 let id = FVarId(self.next_var);
79 self.next_var += 1;
80 id
81 }
82 #[allow(clippy::type_complexity)]
84 pub fn elab_pattern(
85 &mut self,
86 pat: &Pattern,
87 ty: &Expr,
88 ) -> Result<(ElabPattern, Vec<(FVarId, Name, Expr)>), String> {
89 elab_pattern_with_counter(pat, ty, &mut self.next_var)
90 }
91 pub fn check_exhaust(&self, patterns: &[Located<Pattern>]) -> ExhaustivenessResult {
93 check_exhaustive_full(patterns)
94 }
95 pub fn check_redundant_arms(&self, patterns: &[Located<Pattern>]) -> Vec<usize> {
97 check_redundant_full(patterns)
98 }
99}
100#[allow(dead_code)]
102#[derive(Debug, Default)]
103pub struct PatternSubstitution {
104 subst: HashMap<FVarId, Expr>,
106}
107#[allow(dead_code)]
108impl PatternSubstitution {
109 pub fn new() -> Self {
111 Self::default()
112 }
113 pub fn bind(&mut self, fvar: FVarId, expr: Expr) {
115 self.subst.insert(fvar, expr);
116 }
117 pub fn get(&self, fvar: &FVarId) -> Option<&Expr> {
119 self.subst.get(fvar)
120 }
121 pub fn len(&self) -> usize {
123 self.subst.len()
124 }
125 pub fn is_empty(&self) -> bool {
127 self.subst.is_empty()
128 }
129 pub fn apply_to_expr(&self, expr: &Expr) -> Expr {
131 expr.clone()
132 }
133 pub fn merge(&mut self, other: &PatternSubstitution) {
135 for (k, v) in &other.subst {
136 self.subst.insert(*k, v.clone());
137 }
138 }
139}
140#[allow(dead_code)]
142#[derive(Debug, Clone, Copy, PartialEq, Eq)]
143pub enum ColumnHeuristic {
144 LeftMost,
146 MostConstructors,
148 SmallestBranching,
150}
151#[allow(dead_code)]
152impl ColumnHeuristic {
153 pub fn select_column(&self, matrix: &PatternMatrix) -> usize {
155 match self {
156 ColumnHeuristic::LeftMost => 0,
157 ColumnHeuristic::MostConstructors => matrix.best_column(),
158 ColumnHeuristic::SmallestBranching => matrix.best_column(),
159 }
160 }
161}
162#[derive(Clone, Debug, PartialEq)]
164pub enum ElabPattern {
165 Wild,
167 Var(FVarId, Name, Expr),
169 Ctor(Name, Vec<ElabPattern>, Expr),
171 Lit(oxilean_kernel::Literal),
173 Or(Box<ElabPattern>, Box<ElabPattern>),
175 As(FVarId, Name, Box<ElabPattern>),
177 Inaccessible(Expr),
179}
180#[allow(dead_code)]
182#[derive(Debug, Clone, Default)]
183pub struct PatternStats {
184 pub total: usize,
186 pub wilds: usize,
188 pub variables: usize,
190 pub constructors: usize,
192 pub literals: usize,
194 pub ors: usize,
196 pub as_pats: usize,
198 pub inaccessibles: usize,
200 pub max_depth: usize,
202}
203#[allow(dead_code)]
204impl PatternStats {
205 pub fn from_patterns(patterns: &[ElabPattern]) -> Self {
207 let mut stats = Self {
208 total: patterns.len(),
209 ..Self::default()
210 };
211 for pat in patterns {
212 stats.count_pattern(pat);
213 let depth = pattern_depth(pat);
214 if depth > stats.max_depth {
215 stats.max_depth = depth;
216 }
217 }
218 stats
219 }
220 fn count_pattern(&mut self, pat: &ElabPattern) {
221 match pat {
222 ElabPattern::Wild => self.wilds += 1,
223 ElabPattern::Var(_, _, _) => self.variables += 1,
224 ElabPattern::Ctor(_, sub, _) => {
225 self.constructors += 1;
226 for s in sub {
227 self.count_pattern(s);
228 }
229 }
230 ElabPattern::Lit(_) => self.literals += 1,
231 ElabPattern::Or(a, b) => {
232 self.ors += 1;
233 self.count_pattern(a);
234 self.count_pattern(b);
235 }
236 ElabPattern::As(_, _, inner) => {
237 self.as_pats += 1;
238 self.count_pattern(inner);
239 }
240 ElabPattern::Inaccessible(_) => self.inaccessibles += 1,
241 }
242 }
243}
244#[derive(Debug, Clone)]
246pub struct MatchResult {
247 pub expr: Expr,
249 pub defs: Vec<(Name, Expr)>,
251 pub equations: Vec<MatchEquation>,
253 pub missing_patterns: Vec<MissingPattern>,
255 pub redundant_arms: Vec<usize>,
257}
258#[derive(Clone, Debug)]
260pub struct MatchEquation {
261 pub patterns: Vec<ElabPattern>,
263 pub rhs: Expr,
265 pub arm_idx: usize,
267}
268#[derive(Clone, Debug)]
270#[allow(dead_code)]
271pub struct PatternMatrix {
272 pub(super) rows: Vec<MatrixRow>,
274 pub(super) num_cols: usize,
276}
277#[allow(dead_code)]
278impl PatternMatrix {
279 pub(crate) fn from_equations(equations: &[MatchEquation]) -> Self {
281 let num_cols = equations.first().map(|e| e.patterns.len()).unwrap_or(0);
282 let rows = equations
283 .iter()
284 .map(|eq| MatrixRow {
285 patterns: eq.patterns.clone(),
286 rhs_idx: eq.arm_idx,
287 })
288 .collect();
289 Self { rows, num_cols }
290 }
291 pub(crate) fn is_empty(&self) -> bool {
293 self.rows.is_empty()
294 }
295 pub(crate) fn best_column(&self) -> usize {
297 if self.num_cols == 0 {
298 return 0;
299 }
300 let mut best_col = 0;
301 let mut best_score = 0;
302 for col in 0..self.num_cols {
303 let mut ctors = Vec::new();
304 for row in &self.rows {
305 if col < row.patterns.len() {
306 if let ElabPattern::Ctor(name, _, _) = &row.patterns[col] {
307 if !ctors.contains(name) {
308 ctors.push(name.clone());
309 }
310 }
311 }
312 }
313 if ctors.len() > best_score {
314 best_score = ctors.len();
315 best_col = col;
316 }
317 }
318 best_col
319 }
320 pub(super) fn specialize(
325 &self,
326 col: usize,
327 ctor_name: &Name,
328 ctor_arity: usize,
329 ) -> PatternMatrix {
330 let mut new_rows = Vec::new();
331 for row in &self.rows {
332 if col >= row.patterns.len() {
333 continue;
334 }
335 match &row.patterns[col] {
336 ElabPattern::Ctor(name, sub_pats, _) if name == ctor_name => {
337 let mut new_pats = Vec::new();
338 for sp in sub_pats {
339 new_pats.push(sp.clone());
340 }
341 while new_pats.len() < ctor_arity {
342 new_pats.push(ElabPattern::Wild);
343 }
344 for (j, p) in row.patterns.iter().enumerate() {
345 if j != col {
346 new_pats.push(p.clone());
347 }
348 }
349 new_rows.push(MatrixRow {
350 patterns: new_pats,
351 rhs_idx: row.rhs_idx,
352 });
353 }
354 ElabPattern::Wild | ElabPattern::Var(_, _, _) => {
355 let mut new_pats = Vec::new();
356 for _ in 0..ctor_arity {
357 new_pats.push(ElabPattern::Wild);
358 }
359 for (j, p) in row.patterns.iter().enumerate() {
360 if j != col {
361 new_pats.push(p.clone());
362 }
363 }
364 new_rows.push(MatrixRow {
365 patterns: new_pats,
366 rhs_idx: row.rhs_idx,
367 });
368 }
369 _ => {}
370 }
371 }
372 let num_cols = if self.num_cols > 0 {
373 self.num_cols - 1 + ctor_arity
374 } else {
375 ctor_arity
376 };
377 PatternMatrix {
378 rows: new_rows,
379 num_cols,
380 }
381 }
382 pub(super) fn default_matrix(&self, col: usize) -> PatternMatrix {
384 let mut new_rows = Vec::new();
385 for row in &self.rows {
386 if col >= row.patterns.len() {
387 continue;
388 }
389 match &row.patterns[col] {
390 ElabPattern::Wild | ElabPattern::Var(_, _, _) => {
391 let new_pats: Vec<ElabPattern> = row
392 .patterns
393 .iter()
394 .enumerate()
395 .filter(|(j, _)| *j != col)
396 .map(|(_, p)| p.clone())
397 .collect();
398 new_rows.push(MatrixRow {
399 patterns: new_pats,
400 rhs_idx: row.rhs_idx,
401 });
402 }
403 _ => {}
404 }
405 }
406 let num_cols = if self.num_cols > 0 {
407 self.num_cols - 1
408 } else {
409 0
410 };
411 PatternMatrix {
412 rows: new_rows,
413 num_cols,
414 }
415 }
416}
417#[allow(dead_code)]
419pub struct PatternNormalizer;
420#[allow(dead_code)]
421impl PatternNormalizer {
422 pub fn new() -> Self {
424 Self
425 }
426 pub fn normalize(&self, pat: &ElabPattern) -> ElabPattern {
428 match pat {
429 ElabPattern::As(_, _, inner) if is_irrefutable(inner) => self.normalize(inner),
430 ElabPattern::Or(a, b) if a == b => self.normalize(a),
431 ElabPattern::Ctor(name, sub, ty) => {
432 let normalized_sub: Vec<ElabPattern> =
433 sub.iter().map(|s| self.normalize(s)).collect();
434 ElabPattern::Ctor(name.clone(), normalized_sub, ty.clone())
435 }
436 ElabPattern::Or(a, b) => {
437 ElabPattern::Or(Box::new(self.normalize(a)), Box::new(self.normalize(b)))
438 }
439 ElabPattern::As(fv, n, inner) => {
440 ElabPattern::As(*fv, n.clone(), Box::new(self.normalize(inner)))
441 }
442 other => other.clone(),
443 }
444 }
445 pub fn normalize_all(&self, patterns: &[ElabPattern]) -> Vec<ElabPattern> {
447 patterns.iter().map(|p| self.normalize(p)).collect()
448 }
449}
450#[allow(dead_code)]
452pub struct DecisionTreeAnalyzer;
453#[allow(dead_code)]
454impl DecisionTreeAnalyzer {
455 pub fn estimate_depth(tree: &DecisionTree) -> usize {
457 Self::node_depth(&tree.root)
458 }
459 pub fn estimate_nodes(tree: &DecisionTree) -> usize {
461 Self::count_nodes(&tree.root)
462 }
463 pub fn has_default_arm(tree: &DecisionTree) -> bool {
465 Self::node_has_default(&tree.root)
466 }
467 pub fn num_arms(tree: &DecisionTree) -> usize {
469 Self::count_leaves(&tree.root)
470 }
471 fn node_depth(node: &DecisionNode) -> usize {
472 match node {
473 DecisionNode::Leaf(_) | DecisionNode::Fail => 1,
474 DecisionNode::Switch {
475 branches, default, ..
476 } => {
477 let branch_max = branches
478 .iter()
479 .map(|(_, b)| Self::node_depth(b))
480 .max()
481 .unwrap_or(0);
482 let def_depth = default.as_ref().map_or(0, |d| Self::node_depth(d));
483 1 + branch_max.max(def_depth)
484 }
485 DecisionNode::Guard { then, else_, .. } => {
486 1 + Self::node_depth(then).max(Self::node_depth(else_))
487 }
488 }
489 }
490 fn count_nodes(node: &DecisionNode) -> usize {
491 match node {
492 DecisionNode::Leaf(_) | DecisionNode::Fail => 1,
493 DecisionNode::Switch {
494 branches, default, ..
495 } => {
496 let sum: usize = branches.iter().map(|(_, b)| Self::count_nodes(b)).sum();
497 1 + sum + default.as_ref().map_or(0, |d| Self::count_nodes(d))
498 }
499 DecisionNode::Guard { then, else_, .. } => {
500 1 + Self::count_nodes(then) + Self::count_nodes(else_)
501 }
502 }
503 }
504 fn node_has_default(node: &DecisionNode) -> bool {
505 match node {
506 DecisionNode::Leaf(_) | DecisionNode::Fail => false,
507 DecisionNode::Switch {
508 branches, default, ..
509 } => {
510 if default.is_some() {
511 return true;
512 }
513 branches.iter().any(|(_, b)| Self::node_has_default(b))
514 }
515 DecisionNode::Guard { then, else_, .. } => {
516 Self::node_has_default(then) || Self::node_has_default(else_)
517 }
518 }
519 }
520 fn count_leaves(node: &DecisionNode) -> usize {
521 match node {
522 DecisionNode::Leaf(_) => 1,
523 DecisionNode::Fail => 0,
524 DecisionNode::Switch {
525 branches, default, ..
526 } => {
527 let sum: usize = branches.iter().map(|(_, b)| Self::count_leaves(b)).sum();
528 sum + default.as_ref().map_or(0, |d| Self::count_leaves(d))
529 }
530 DecisionNode::Guard { then, else_, .. } => {
531 Self::count_leaves(then) + Self::count_leaves(else_)
532 }
533 }
534 }
535}
536#[derive(Debug, Clone)]
538#[allow(dead_code)]
539pub enum DecisionNode {
540 Leaf(Expr),
542 Switch {
544 var: Name,
546 branches: Vec<(Name, Box<DecisionNode>)>,
548 default: Option<Box<DecisionNode>>,
550 },
551 Guard {
553 condition: Expr,
555 then: Box<DecisionNode>,
557 else_: Box<DecisionNode>,
559 },
560 Fail,
562}
563#[allow(dead_code)]
565#[derive(Debug, Clone, Default)]
566pub struct LiteralSet {
567 pub nats: Vec<u64>,
569 pub strings: Vec<String>,
571 pub has_wildcard: bool,
573}
574#[allow(dead_code)]
575impl LiteralSet {
576 pub fn new() -> Self {
578 Self::default()
579 }
580 pub fn add_literal(&mut self, lit: &oxilean_kernel::Literal) {
582 match lit {
583 oxilean_kernel::Literal::Nat(n) => {
584 if !self.nats.contains(n) {
585 self.nats.push(*n);
586 }
587 }
588 oxilean_kernel::Literal::Str(s) => {
589 if !self.strings.contains(s) {
590 self.strings.push(s.clone());
591 }
592 }
593 }
594 }
595 pub fn add_wildcard(&mut self) {
597 self.has_wildcard = true;
598 }
599 pub fn covers_nat(&self, n: u64) -> bool {
601 self.has_wildcard || self.nats.contains(&n)
602 }
603 pub fn num_specific(&self) -> usize {
605 self.nats.len() + self.strings.len()
606 }
607}
608#[allow(dead_code)]
610#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
611pub enum PatternKind {
612 Wild,
614 Variable,
616 Constructor,
618 Literal,
620 Or,
622 As,
624 Inaccessible,
626}
627#[allow(dead_code)]
628impl PatternKind {
629 pub fn of(pat: &ElabPattern) -> Self {
631 match pat {
632 ElabPattern::Wild => PatternKind::Wild,
633 ElabPattern::Var(_, _, _) => PatternKind::Variable,
634 ElabPattern::Ctor(_, _, _) => PatternKind::Constructor,
635 ElabPattern::Lit(_) => PatternKind::Literal,
636 ElabPattern::Or(_, _) => PatternKind::Or,
637 ElabPattern::As(_, _, _) => PatternKind::As,
638 ElabPattern::Inaccessible(_) => PatternKind::Inaccessible,
639 }
640 }
641 pub fn can_bind(&self) -> bool {
643 matches!(self, PatternKind::Variable | PatternKind::As)
644 }
645 pub fn is_catch_all(&self) -> bool {
647 matches!(self, PatternKind::Wild | PatternKind::Variable)
648 }
649}
650#[derive(Clone, Debug)]
652pub struct ExhaustivenessResult {
653 pub is_exhaustive: bool,
655 pub missing: Vec<MissingPattern>,
657}
658#[derive(Clone, Debug)]
660#[allow(dead_code)]
661pub struct MatrixRow {
662 pub patterns: Vec<ElabPattern>,
663 pub rhs_idx: usize,
664}
665#[allow(dead_code)]
667#[derive(Debug, Clone, Default)]
668pub struct MatchCoverage {
669 pub num_arms: usize,
671 pub hit: Vec<bool>,
673}
674#[allow(dead_code)]
675impl MatchCoverage {
676 pub fn new(n: usize) -> Self {
678 Self {
679 num_arms: n,
680 hit: vec![false; n],
681 }
682 }
683 pub fn record_hit(&mut self, i: usize) {
685 if i < self.num_arms {
686 self.hit[i] = true;
687 }
688 }
689 pub fn arms_hit(&self) -> usize {
691 self.hit.iter().filter(|&&h| h).count()
692 }
693 pub fn is_full_coverage(&self) -> bool {
695 self.hit.iter().all(|&h| h)
696 }
697 pub fn uncovered_arms(&self) -> Vec<usize> {
699 self.hit
700 .iter()
701 .enumerate()
702 .filter(|(_, &h)| !h)
703 .map(|(i, _)| i)
704 .collect()
705 }
706 pub fn coverage_pct(&self) -> f64 {
708 if self.num_arms == 0 {
709 1.0
710 } else {
711 self.arms_hit() as f64 / self.num_arms as f64
712 }
713 }
714}
715#[allow(dead_code)]
717pub struct PatternPrinter {
718 pub indent: usize,
720}
721#[allow(dead_code)]
722impl PatternPrinter {
723 pub fn new() -> Self {
725 Self { indent: 2 }
726 }
727 pub fn with_indent(indent: usize) -> Self {
729 Self { indent }
730 }
731 pub fn print(&self, pat: &ElabPattern) -> String {
733 self.print_inner(pat, 0)
734 }
735 fn print_inner(&self, pat: &ElabPattern, _depth: usize) -> String {
736 match pat {
737 ElabPattern::Wild => "_".to_string(),
738 ElabPattern::Var(_, name, _) => format!("{}", name),
739 ElabPattern::Lit(lit) => match lit {
740 oxilean_kernel::Literal::Nat(n) => format!("{}", n),
741 oxilean_kernel::Literal::Str(s) => format!("\"{}\"", s),
742 },
743 ElabPattern::Ctor(name, sub, _) => {
744 if sub.is_empty() {
745 format!("{}", name)
746 } else {
747 let args: Vec<String> = sub
748 .iter()
749 .map(|s| self.print_inner(s, _depth + 1))
750 .collect();
751 format!("({} {})", name, args.join(" "))
752 }
753 }
754 ElabPattern::Or(a, b) => {
755 format!(
756 "({} | {})",
757 self.print_inner(a, _depth),
758 self.print_inner(b, _depth)
759 )
760 }
761 ElabPattern::As(_, name, inner) => {
762 format!("({} @ {})", self.print_inner(inner, _depth), name)
763 }
764 ElabPattern::Inaccessible(e) => format!(".({})", e),
765 }
766 }
767 pub fn print_all(&self, patterns: &[ElabPattern]) -> String {
769 patterns
770 .iter()
771 .enumerate()
772 .map(|(i, p)| format!(" arm {}: {}", i, self.print(p)))
773 .collect::<Vec<_>>()
774 .join("\n")
775 }
776}
777pub struct PatternCompiler {
781 pub(crate) next_var: u32,
783}
784impl PatternCompiler {
785 pub fn new() -> Self {
787 Self { next_var: 0 }
788 }
789 pub fn fresh_var(&mut self) -> Name {
791 let n = self.next_var;
792 self.next_var += 1;
793 Name::str(format!("_pat{}", n))
794 }
795 pub fn compile(
797 &mut self,
798 patterns: &[(Located<Pattern>, Located<SurfaceExpr>)],
799 ) -> Result<DecisionTree, String> {
800 DecisionTree::new(patterns)
801 }
802 #[allow(dead_code)]
804 pub fn compile_equations(
805 &mut self,
806 equations: &[MatchEquation],
807 ) -> Result<DecisionTree, String> {
808 DecisionTree::from_equations(equations)
809 }
810 #[allow(dead_code)]
812 pub fn from_match_arms(
813 &mut self,
814 ctx: &mut ElabContext,
815 _scrutinee_ty: &Expr,
816 arms: &[MatchArm],
817 ) -> Result<(DecisionTree, MatchResult), String> {
818 let mut equations = Vec::new();
819 for (i, arm) in arms.iter().enumerate() {
820 let expected_ty = Expr::Sort(Level::succ(Level::zero()));
821 let (elab_pat, _bindings) = elaborate_pattern(ctx, &arm.pattern.value, &expected_ty)?;
822 let rhs = surface_to_placeholder(&arm.rhs.value);
823 let guard_expr = arm.guard.as_ref().map(|g| surface_to_placeholder(&g.value));
824 let _ = guard_expr;
825 equations.push(MatchEquation {
826 patterns: vec![elab_pat],
827 rhs,
828 arm_idx: i,
829 });
830 }
831 let tree = DecisionTree::from_equations(&equations)?;
832 let expr = tree.compile();
833 let patterns_located: Vec<Located<Pattern>> =
834 arms.iter().map(|a| a.pattern.clone()).collect();
835 let exhaustiveness = check_exhaustive_full(&patterns_located);
836 let redundant = check_redundant_full(&patterns_located);
837 let result = MatchResult {
838 expr,
839 defs: Vec::new(),
840 equations,
841 missing_patterns: exhaustiveness.missing,
842 redundant_arms: redundant,
843 };
844 Ok((tree, result))
845 }
846}
847#[derive(Clone, Debug)]
849pub struct MissingPattern {
850 pub ctor_name: Name,
852 pub sub_patterns: Vec<ElabPattern>,
854}
855#[allow(dead_code)]
859pub struct PatternMatcher {
860 pub partial_ok: bool,
862}
863#[allow(dead_code)]
864impl PatternMatcher {
865 pub fn new() -> Self {
867 Self { partial_ok: false }
868 }
869 pub fn matches_literal(&self, pat: &ElabPattern, lit: &oxilean_kernel::Literal) -> bool {
871 match pat {
872 ElabPattern::Wild | ElabPattern::Var(_, _, _) => true,
873 ElabPattern::Lit(l) => l == lit,
874 ElabPattern::Or(a, b) => self.matches_literal(a, lit) || self.matches_literal(b, lit),
875 ElabPattern::As(_, _, inner) => self.matches_literal(inner, lit),
876 ElabPattern::Ctor(_, _, _) | ElabPattern::Inaccessible(_) => false,
877 }
878 }
879 pub fn first_match_idx(
881 &self,
882 arms: &[ElabPattern],
883 lit: &oxilean_kernel::Literal,
884 ) -> Option<usize> {
885 arms.iter().position(|p| self.matches_literal(p, lit))
886 }
887 pub fn all_match_idxs(
889 &self,
890 arms: &[ElabPattern],
891 lit: &oxilean_kernel::Literal,
892 ) -> Vec<usize> {
893 arms.iter()
894 .enumerate()
895 .filter(|(_, p)| self.matches_literal(p, lit))
896 .map(|(i, _)| i)
897 .collect()
898 }
899}