cranelift_isle/
overlap.rs1use std::collections::hash_map::Entry;
4use std::collections::{HashMap, HashSet};
5
6use crate::error::{Error, Span};
7use crate::lexer::Pos;
8use crate::sema::{TermEnv, TermId, TermKind};
9use crate::trie_again;
10
11pub fn check(termenv: &TermEnv) -> Result<Vec<(TermId, trie_again::RuleSet)>, Vec<Error>> {
13 let (terms, mut errors) = trie_again::build(termenv);
14 errors.append(&mut check_overlaps(&terms, termenv).report());
15
16 if errors.is_empty() {
17 Ok(terms)
18 } else {
19 Err(errors)
20 }
21}
22
23#[derive(Default)]
25struct Errors {
26 nodes: HashMap<Pos, HashSet<Pos>>,
28 shadowed: HashMap<Pos, Vec<Pos>>,
31}
32
33impl Errors {
34 fn report(mut self) -> Vec<Error> {
39 let mut errors = Vec::new();
40
41 while let Some((&pos, _)) = self
42 .nodes
43 .iter()
44 .max_by_key(|(pos, edges)| (edges.len(), *pos))
45 {
46 let node = self.nodes.remove(&pos).unwrap();
47 for other in node.iter() {
48 if let Entry::Occupied(mut entry) = self.nodes.entry(*other) {
49 let back_edges = entry.get_mut();
50 back_edges.remove(&pos);
51 if back_edges.is_empty() {
52 entry.remove();
53 }
54 }
55 }
56
57 let mut rules = vec![Span::new_single(pos)];
59
60 rules.extend(node.into_iter().map(Span::new_single));
61
62 errors.push(Error::OverlapError {
63 msg: String::from("rules are overlapping"),
64 rules,
65 });
66 }
67
68 errors.extend(
69 self.shadowed
70 .into_iter()
71 .map(|(mask, shadowed)| Error::ShadowedError {
72 shadowed: shadowed.into_iter().map(Span::new_single).collect(),
73 mask: Span::new_single(mask),
74 }),
75 );
76
77 errors.sort_by_key(|err| match err {
78 Error::ShadowedError { mask, .. } => mask.from,
79 Error::OverlapError { rules, .. } => rules[0].from,
80 _ => Pos::default(),
81 });
82 errors
83 }
84
85 fn check_pair(&mut self, a: &trie_again::Rule, b: &trie_again::Rule) {
86 if let trie_again::Overlap::Yes { subset } = a.may_overlap(b) {
87 if a.prio == b.prio {
88 self.nodes.entry(a.pos).or_default().insert(b.pos);
90 self.nodes.entry(b.pos).or_default().insert(a.pos);
91 } else if subset {
92 let (lo, hi) = if a.prio < b.prio { (a, b) } else { (b, a) };
95 if hi.total_constraints() <= lo.total_constraints() {
96 self.shadowed.entry(hi.pos).or_default().push(lo.pos);
98 }
99 }
100 }
101 }
102}
103
104fn check_overlaps(terms: &[(TermId, trie_again::RuleSet)], env: &TermEnv) -> Errors {
108 let mut errs = Errors::default();
109 for (tid, ruleset) in terms {
110 let is_multi_ctor = match &env.terms[tid.index()].kind {
111 TermKind::Decl { flags, .. } => flags.multi,
112 _ => false,
113 };
114 if is_multi_ctor {
115 continue;
120 }
121
122 let mut cursor = ruleset.rules.iter();
123 while let Some(left) = cursor.next() {
124 for right in cursor.as_slice() {
125 errs.check_pair(left, right);
126 }
127 }
128 }
129 errs
130}