Skip to main content

litex/fact/
mark_forall_param_coverage.rs

1use crate::prelude::*;
2use std::collections::HashMap;
3
4// coverage_by_forall_param: one entry per forall parameter, values start false.
5// Walk the clause: Identifier or FieldAccess base name appears and is a key -> set true.
6
7fn mark_forall_param_name_if_tracked(
8    coverage_by_forall_param: &mut HashMap<IdentifierName, bool>,
9    name: &IdentifierName,
10) {
11    match coverage_by_forall_param.get_mut(name) {
12        Some(is_mentioned) => {
13            *is_mentioned = true;
14        }
15        None => {}
16    }
17}
18
19fn mark_forall_param_coverage_in_param_type(
20    param_type: &ParamType,
21    coverage_by_forall_param: &mut HashMap<IdentifierName, bool>,
22) {
23    match param_type {
24        ParamType::Obj(obj) => {
25            mark_forall_param_coverage_in_obj(obj, coverage_by_forall_param);
26        }
27        ParamType::Set(_) | ParamType::NonemptySet(_) | ParamType::FiniteSet(_) => {}
28        ParamType::Struct(struct_ty) => {
29            for param_obj in struct_ty.args.iter() {
30                mark_forall_param_coverage_in_obj(param_obj, coverage_by_forall_param);
31            }
32        }
33    }
34}
35
36fn mark_forall_param_coverage_in_atom(
37    atom: &Atom,
38    coverage_by_forall_param: &mut HashMap<IdentifierName, bool>,
39) {
40    match atom {
41        Atom::Identifier(identifier) => {
42            mark_forall_param_name_if_tracked(coverage_by_forall_param, &identifier.name);
43        }
44        Atom::IdentifierWithMod(_) => {}
45        Atom::FieldAccess(field_access) => {
46            mark_forall_param_name_if_tracked(coverage_by_forall_param, &field_access.name);
47        }
48        Atom::FieldAccessWithMod(_) => {}
49    }
50}
51
52fn mark_forall_param_coverage_in_obj(
53    obj: &Obj,
54    coverage_by_forall_param: &mut HashMap<IdentifierName, bool>,
55) {
56    match obj {
57        Obj::Identifier(identifier) => {
58            mark_forall_param_name_if_tracked(coverage_by_forall_param, &identifier.name);
59        }
60        Obj::IdentifierWithMod(_) => {}
61        Obj::FieldAccess(field_access) => {
62            mark_forall_param_name_if_tracked(coverage_by_forall_param, &field_access.name);
63        }
64        Obj::FieldAccessWithMod(_) => {}
65        Obj::FnObj(fn_obj) => {
66            mark_forall_param_coverage_in_atom(fn_obj.head.as_ref(), coverage_by_forall_param);
67            for group in fn_obj.body.iter() {
68                for boxed_obj in group.iter() {
69                    mark_forall_param_coverage_in_obj(boxed_obj.as_ref(), coverage_by_forall_param);
70                }
71            }
72        }
73        Obj::Number(_) | Obj::StandardSet(_) => {}
74        Obj::Add(binary) => {
75            mark_forall_param_coverage_in_obj(binary.left.as_ref(), coverage_by_forall_param);
76            mark_forall_param_coverage_in_obj(binary.right.as_ref(), coverage_by_forall_param);
77        }
78        Obj::Sub(binary) => {
79            mark_forall_param_coverage_in_obj(binary.left.as_ref(), coverage_by_forall_param);
80            mark_forall_param_coverage_in_obj(binary.right.as_ref(), coverage_by_forall_param);
81        }
82        Obj::Mul(binary) => {
83            mark_forall_param_coverage_in_obj(binary.left.as_ref(), coverage_by_forall_param);
84            mark_forall_param_coverage_in_obj(binary.right.as_ref(), coverage_by_forall_param);
85        }
86        Obj::Div(binary) => {
87            mark_forall_param_coverage_in_obj(binary.left.as_ref(), coverage_by_forall_param);
88            mark_forall_param_coverage_in_obj(binary.right.as_ref(), coverage_by_forall_param);
89        }
90        Obj::Mod(binary) => {
91            mark_forall_param_coverage_in_obj(binary.left.as_ref(), coverage_by_forall_param);
92            mark_forall_param_coverage_in_obj(binary.right.as_ref(), coverage_by_forall_param);
93        }
94        Obj::Pow(binary) => {
95            mark_forall_param_coverage_in_obj(binary.base.as_ref(), coverage_by_forall_param);
96            mark_forall_param_coverage_in_obj(binary.exponent.as_ref(), coverage_by_forall_param);
97        }
98        Obj::Union(binary) => {
99            mark_forall_param_coverage_in_obj(binary.left.as_ref(), coverage_by_forall_param);
100            mark_forall_param_coverage_in_obj(binary.right.as_ref(), coverage_by_forall_param);
101        }
102        Obj::Intersect(binary) => {
103            mark_forall_param_coverage_in_obj(binary.left.as_ref(), coverage_by_forall_param);
104            mark_forall_param_coverage_in_obj(binary.right.as_ref(), coverage_by_forall_param);
105        }
106        Obj::SetMinus(binary) => {
107            mark_forall_param_coverage_in_obj(binary.left.as_ref(), coverage_by_forall_param);
108            mark_forall_param_coverage_in_obj(binary.right.as_ref(), coverage_by_forall_param);
109        }
110        Obj::SetDiff(binary) => {
111            mark_forall_param_coverage_in_obj(binary.left.as_ref(), coverage_by_forall_param);
112            mark_forall_param_coverage_in_obj(binary.right.as_ref(), coverage_by_forall_param);
113        }
114        Obj::Cup(unary) => {
115            mark_forall_param_coverage_in_obj(unary.left.as_ref(), coverage_by_forall_param);
116        }
117        Obj::Cap(unary) => {
118            mark_forall_param_coverage_in_obj(unary.left.as_ref(), coverage_by_forall_param);
119        }
120        Obj::PowerSet(unary) => {
121            mark_forall_param_coverage_in_obj(unary.set.as_ref(), coverage_by_forall_param);
122        }
123        Obj::ListSet(list_set) => {
124            for boxed_obj in list_set.list.iter() {
125                mark_forall_param_coverage_in_obj(boxed_obj.as_ref(), coverage_by_forall_param);
126            }
127        }
128        Obj::SetBuilder(set_builder) => {
129            mark_forall_param_coverage_in_obj(
130                set_builder.param_set.as_ref(),
131                coverage_by_forall_param,
132            );
133            for inner_fact in set_builder.facts.iter() {
134                mark_forall_param_coverage_in_or_and_chain_atomic_fact(
135                    inner_fact,
136                    coverage_by_forall_param,
137                );
138            }
139        }
140        Obj::FnSet(fn_set) => {
141            for param_def_with_set in fn_set.params_def_with_set.iter() {
142                mark_forall_param_coverage_in_obj(
143                    &param_def_with_set.set,
144                    coverage_by_forall_param,
145                );
146            }
147            for dom_fact in fn_set.dom_facts.iter() {
148                mark_forall_param_coverage_in_or_and_chain_atomic_fact(
149                    dom_fact,
150                    coverage_by_forall_param,
151                );
152            }
153            mark_forall_param_coverage_in_obj(fn_set.ret_set.as_ref(), coverage_by_forall_param);
154        }
155        Obj::Cart(cart) => {
156            for boxed_arg in cart.args.iter() {
157                mark_forall_param_coverage_in_obj(boxed_arg.as_ref(), coverage_by_forall_param);
158            }
159        }
160        Obj::CartDim(cart_dim) => {
161            mark_forall_param_coverage_in_obj(cart_dim.set.as_ref(), coverage_by_forall_param);
162        }
163        Obj::Proj(proj) => {
164            mark_forall_param_coverage_in_obj(proj.set.as_ref(), coverage_by_forall_param);
165            mark_forall_param_coverage_in_obj(proj.dim.as_ref(), coverage_by_forall_param);
166        }
167        Obj::TupleDim(tuple_dim) => {
168            mark_forall_param_coverage_in_obj(tuple_dim.arg.as_ref(), coverage_by_forall_param);
169        }
170        Obj::Tuple(tuple_obj) => {
171            for boxed_arg in tuple_obj.args.iter() {
172                mark_forall_param_coverage_in_obj(boxed_arg.as_ref(), coverage_by_forall_param);
173            }
174        }
175        Obj::Count(count) => {
176            mark_forall_param_coverage_in_obj(count.set.as_ref(), coverage_by_forall_param);
177        }
178        Obj::Range(range) => {
179            mark_forall_param_coverage_in_obj(range.start.as_ref(), coverage_by_forall_param);
180            mark_forall_param_coverage_in_obj(range.end.as_ref(), coverage_by_forall_param);
181        }
182        Obj::ClosedRange(closed_range) => {
183            mark_forall_param_coverage_in_obj(
184                closed_range.start.as_ref(),
185                coverage_by_forall_param,
186            );
187            mark_forall_param_coverage_in_obj(closed_range.end.as_ref(), coverage_by_forall_param);
188        }
189        Obj::Choose(choose) => {
190            mark_forall_param_coverage_in_obj(choose.set.as_ref(), coverage_by_forall_param);
191        }
192        Obj::ObjAtIndex(obj_at_index) => {
193            mark_forall_param_coverage_in_obj(obj_at_index.obj.as_ref(), coverage_by_forall_param);
194            mark_forall_param_coverage_in_obj(
195                obj_at_index.index.as_ref(),
196                coverage_by_forall_param,
197            );
198        }
199        Obj::FamilyObj(family) => {
200            for param_obj in family.params.iter() {
201                mark_forall_param_coverage_in_obj(param_obj, coverage_by_forall_param);
202            }
203        }
204        Obj::StructObj(struct_ty) => {
205            for param_obj in struct_ty.args.iter() {
206                mark_forall_param_coverage_in_obj(param_obj, coverage_by_forall_param);
207            }
208        }
209    }
210}
211
212fn mark_forall_param_coverage_in_atomic_fact(
213    atomic_fact: &AtomicFact,
214    coverage_by_forall_param: &mut HashMap<IdentifierName, bool>,
215) {
216    match atomic_fact {
217        AtomicFact::NormalAtomicFact(fact) => {
218            for body_obj in fact.body.iter() {
219                mark_forall_param_coverage_in_obj(body_obj, coverage_by_forall_param);
220            }
221        }
222        AtomicFact::NotNormalAtomicFact(fact) => {
223            for body_obj in fact.body.iter() {
224                mark_forall_param_coverage_in_obj(body_obj, coverage_by_forall_param);
225            }
226        }
227        AtomicFact::EqualFact(fact) => {
228            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
229            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
230        }
231        AtomicFact::LessFact(fact) => {
232            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
233            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
234        }
235        AtomicFact::GreaterFact(fact) => {
236            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
237            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
238        }
239        AtomicFact::LessEqualFact(fact) => {
240            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
241            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
242        }
243        AtomicFact::GreaterEqualFact(fact) => {
244            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
245            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
246        }
247        AtomicFact::NotEqualFact(fact) => {
248            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
249            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
250        }
251        AtomicFact::NotLessFact(fact) => {
252            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
253            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
254        }
255        AtomicFact::NotGreaterFact(fact) => {
256            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
257            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
258        }
259        AtomicFact::NotLessEqualFact(fact) => {
260            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
261            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
262        }
263        AtomicFact::NotGreaterEqualFact(fact) => {
264            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
265            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
266        }
267        AtomicFact::IsSetFact(fact) => {
268            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
269        }
270        AtomicFact::NotIsSetFact(fact) => {
271            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
272        }
273        AtomicFact::IsNonemptySetFact(fact) => {
274            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
275        }
276        AtomicFact::NotIsNonemptySetFact(fact) => {
277            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
278        }
279        AtomicFact::IsFiniteSetFact(fact) => {
280            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
281        }
282        AtomicFact::NotIsFiniteSetFact(fact) => {
283            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
284        }
285        AtomicFact::InFact(fact) => {
286            mark_forall_param_coverage_in_obj(&fact.element, coverage_by_forall_param);
287            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
288        }
289        AtomicFact::NotInFact(fact) => {
290            mark_forall_param_coverage_in_obj(&fact.element, coverage_by_forall_param);
291            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
292        }
293        AtomicFact::IsCartFact(fact) => {
294            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
295        }
296        AtomicFact::NotIsCartFact(fact) => {
297            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
298        }
299        AtomicFact::IsTupleFact(fact) => {
300            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
301        }
302        AtomicFact::NotIsTupleFact(fact) => {
303            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
304        }
305        AtomicFact::SubsetFact(fact) => {
306            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
307            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
308        }
309        AtomicFact::SupersetFact(fact) => {
310            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
311            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
312        }
313        AtomicFact::NotSubsetFact(fact) => {
314            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
315            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
316        }
317        AtomicFact::NotSupersetFact(fact) => {
318            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
319            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
320        }
321        AtomicFact::RestrictFact(fact) => {
322            mark_forall_param_coverage_in_obj(&fact.obj, coverage_by_forall_param);
323            mark_forall_param_coverage_in_obj(
324                &fact.obj_can_restrict_to_fn_set,
325                coverage_by_forall_param,
326            );
327        }
328        AtomicFact::NotRestrictFact(fact) => {
329            mark_forall_param_coverage_in_obj(&fact.obj, coverage_by_forall_param);
330            mark_forall_param_coverage_in_obj(
331                &fact.obj_cannot_restrict_to_fn_set,
332                coverage_by_forall_param,
333            );
334        }
335    }
336}
337
338fn mark_forall_param_coverage_in_and_chain_atomic_fact(
339    parent_fact: &AndChainAtomicFact,
340    coverage_by_forall_param: &mut HashMap<IdentifierName, bool>,
341) {
342    match parent_fact {
343        AndChainAtomicFact::AtomicFact(atomic_fact) => {
344            mark_forall_param_coverage_in_atomic_fact(atomic_fact, coverage_by_forall_param);
345        }
346        AndChainAtomicFact::AndFact(and_fact) => {
347            for inner_atomic in and_fact.facts.iter() {
348                mark_forall_param_coverage_in_atomic_fact(inner_atomic, coverage_by_forall_param);
349            }
350        }
351        AndChainAtomicFact::ChainFact(chain_fact) => {
352            for chain_obj in chain_fact.objs.iter() {
353                mark_forall_param_coverage_in_obj(chain_obj, coverage_by_forall_param);
354            }
355        }
356    }
357}
358
359fn mark_forall_param_coverage_in_or_and_chain_atomic_fact(
360    parent_fact: &OrAndChainAtomicFact,
361    coverage_by_forall_param: &mut HashMap<IdentifierName, bool>,
362) {
363    match parent_fact {
364        OrAndChainAtomicFact::AtomicFact(atomic_fact) => {
365            mark_forall_param_coverage_in_atomic_fact(atomic_fact, coverage_by_forall_param);
366        }
367        OrAndChainAtomicFact::AndFact(and_fact) => {
368            for inner_atomic in and_fact.facts.iter() {
369                mark_forall_param_coverage_in_atomic_fact(inner_atomic, coverage_by_forall_param);
370            }
371        }
372        OrAndChainAtomicFact::ChainFact(chain_fact) => {
373            for chain_obj in chain_fact.objs.iter() {
374                mark_forall_param_coverage_in_obj(chain_obj, coverage_by_forall_param);
375            }
376        }
377        OrAndChainAtomicFact::OrFact(or_fact) => {
378            for branch in or_fact.facts.iter() {
379                mark_forall_param_coverage_in_and_chain_atomic_fact(
380                    branch,
381                    coverage_by_forall_param,
382                );
383            }
384        }
385    }
386}
387
388fn mark_forall_param_coverage_in_exist_fact(
389    exist_fact: &ExistFact,
390    coverage_by_forall_param: &mut HashMap<IdentifierName, bool>,
391) {
392    for param_def_with_type in exist_fact.params_def_with_type.iter() {
393        mark_forall_param_coverage_in_param_type(
394            &param_def_with_type.param_type,
395            coverage_by_forall_param,
396        );
397    }
398    for inner_fact in exist_fact.facts.iter() {
399        mark_forall_param_coverage_in_or_and_chain_atomic_fact(
400            inner_fact,
401            coverage_by_forall_param,
402        );
403    }
404}
405
406fn mark_forall_param_coverage_in_exist_or_and_chain_atomic_fact(
407    parent_fact: &ExistOrAndChainAtomicFact,
408    coverage_by_forall_param: &mut HashMap<IdentifierName, bool>,
409) {
410    match parent_fact {
411        ExistOrAndChainAtomicFact::AtomicFact(atomic_fact) => {
412            mark_forall_param_coverage_in_atomic_fact(atomic_fact, coverage_by_forall_param);
413        }
414        ExistOrAndChainAtomicFact::AndFact(and_fact) => {
415            for inner_atomic in and_fact.facts.iter() {
416                mark_forall_param_coverage_in_atomic_fact(inner_atomic, coverage_by_forall_param);
417            }
418        }
419        ExistOrAndChainAtomicFact::ChainFact(chain_fact) => {
420            for chain_obj in chain_fact.objs.iter() {
421                mark_forall_param_coverage_in_obj(chain_obj, coverage_by_forall_param);
422            }
423        }
424        ExistOrAndChainAtomicFact::OrFact(or_fact) => {
425            for branch in or_fact.facts.iter() {
426                mark_forall_param_coverage_in_and_chain_atomic_fact(
427                    branch,
428                    coverage_by_forall_param,
429                );
430            }
431        }
432        ExistOrAndChainAtomicFact::ExistFact(exist_fact) => {
433            mark_forall_param_coverage_in_exist_fact(exist_fact, coverage_by_forall_param);
434        }
435    }
436}
437
438impl ForallFact {
439    pub fn error_messages_if_forall_param_missing_in_some_then_clause(&self) -> Vec<(usize, String)> {
440        let forall_param_names =
441            ParamGroupWithParamType::collect_param_names(&self.params_def_with_type);
442        if forall_param_names.is_empty() {
443            return Vec::new();
444        }
445        let mut error_messages = Vec::new();
446        let mut then_index: usize = 0;
447        while then_index < self.then_facts.len() {
448            let then_fact = &self.then_facts[then_index];
449            let mut coverage_by_forall_param: HashMap<IdentifierName, bool> = HashMap::new();
450            for param_name in forall_param_names.iter() {
451                coverage_by_forall_param.insert(param_name.clone(), false);
452            }
453            mark_forall_param_coverage_in_exist_or_and_chain_atomic_fact(
454                then_fact,
455                &mut coverage_by_forall_param,
456            );
457            let mut missing_param_names = Vec::new();
458            for param_name in forall_param_names.iter() {
459                let is_mentioned_in_then_clause = match coverage_by_forall_param.get(param_name) {
460                    Some(flag) => *flag,
461                    None => false,
462                };
463                if !is_mentioned_in_then_clause {
464                    missing_param_names.push(param_name.clone());
465                }
466            }
467            if !missing_param_names.is_empty() {
468                let missing_list = missing_param_names.join(", ");
469                error_messages.push((
470                    then_index,
471                    format!(
472                        "then-clause `{}` does not mention forall parameter(s) {{{}}}",
473                        then_fact, missing_list,
474                    ),
475                ));
476            }
477            then_index += 1;
478        }
479        error_messages
480    }
481}
482
483impl ForallFactWithIff {
484    /// Only checks the embedded [`ForallFact`]'s `then_facts` (not `iff_facts`).
485    pub fn error_messages_if_forall_param_missing_in_forall_then_clause(&self) -> Vec<(usize, String)> {
486        self.forall_fact
487            .error_messages_if_forall_param_missing_in_some_then_clause()
488    }
489}