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::MatrixAdd(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::MatrixSub(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::MatrixMul(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::MatrixScalarMul(binary) => {
111            mark_forall_param_coverage_in_obj(binary.scalar.as_ref(), coverage_by_forall_param);
112            mark_forall_param_coverage_in_obj(binary.matrix.as_ref(), coverage_by_forall_param);
113        }
114        Obj::MatrixPow(binary) => {
115            mark_forall_param_coverage_in_obj(binary.base.as_ref(), coverage_by_forall_param);
116            mark_forall_param_coverage_in_obj(binary.exponent.as_ref(), coverage_by_forall_param);
117        }
118        Obj::Abs(unary) => {
119            mark_forall_param_coverage_in_obj(unary.arg.as_ref(), coverage_by_forall_param);
120        }
121        Obj::Log(binary) => {
122            mark_forall_param_coverage_in_obj(binary.base.as_ref(), coverage_by_forall_param);
123            mark_forall_param_coverage_in_obj(binary.arg.as_ref(), coverage_by_forall_param);
124        }
125        Obj::Max(binary) => {
126            mark_forall_param_coverage_in_obj(binary.left.as_ref(), coverage_by_forall_param);
127            mark_forall_param_coverage_in_obj(binary.right.as_ref(), coverage_by_forall_param);
128        }
129        Obj::Min(binary) => {
130            mark_forall_param_coverage_in_obj(binary.left.as_ref(), coverage_by_forall_param);
131            mark_forall_param_coverage_in_obj(binary.right.as_ref(), coverage_by_forall_param);
132        }
133        Obj::Union(binary) => {
134            mark_forall_param_coverage_in_obj(binary.left.as_ref(), coverage_by_forall_param);
135            mark_forall_param_coverage_in_obj(binary.right.as_ref(), coverage_by_forall_param);
136        }
137        Obj::Intersect(binary) => {
138            mark_forall_param_coverage_in_obj(binary.left.as_ref(), coverage_by_forall_param);
139            mark_forall_param_coverage_in_obj(binary.right.as_ref(), coverage_by_forall_param);
140        }
141        Obj::SetMinus(binary) => {
142            mark_forall_param_coverage_in_obj(binary.left.as_ref(), coverage_by_forall_param);
143            mark_forall_param_coverage_in_obj(binary.right.as_ref(), coverage_by_forall_param);
144        }
145        Obj::SetDiff(binary) => {
146            mark_forall_param_coverage_in_obj(binary.left.as_ref(), coverage_by_forall_param);
147            mark_forall_param_coverage_in_obj(binary.right.as_ref(), coverage_by_forall_param);
148        }
149        Obj::Cup(unary) => {
150            mark_forall_param_coverage_in_obj(unary.left.as_ref(), coverage_by_forall_param);
151        }
152        Obj::Cap(unary) => {
153            mark_forall_param_coverage_in_obj(unary.left.as_ref(), coverage_by_forall_param);
154        }
155        Obj::PowerSet(unary) => {
156            mark_forall_param_coverage_in_obj(unary.set.as_ref(), coverage_by_forall_param);
157        }
158        Obj::ListSet(list_set) => {
159            for boxed_obj in list_set.list.iter() {
160                mark_forall_param_coverage_in_obj(boxed_obj.as_ref(), coverage_by_forall_param);
161            }
162        }
163        Obj::SetBuilder(set_builder) => {
164            mark_forall_param_coverage_in_obj(
165                set_builder.param_set.as_ref(),
166                coverage_by_forall_param,
167            );
168            for inner_fact in set_builder.facts.iter() {
169                mark_forall_param_coverage_in_or_and_chain_atomic_fact(
170                    inner_fact,
171                    coverage_by_forall_param,
172                );
173            }
174        }
175        Obj::FnSet(fn_set) => {
176            for param_def_with_set in fn_set.params_def_with_set.iter() {
177                mark_forall_param_coverage_in_obj(
178                    &param_def_with_set.set,
179                    coverage_by_forall_param,
180                );
181            }
182            for dom_fact in fn_set.dom_facts.iter() {
183                mark_forall_param_coverage_in_or_and_chain_atomic_fact(
184                    dom_fact,
185                    coverage_by_forall_param,
186                );
187            }
188            mark_forall_param_coverage_in_obj(fn_set.ret_set.as_ref(), coverage_by_forall_param);
189        }
190        Obj::Cart(cart) => {
191            for boxed_arg in cart.args.iter() {
192                mark_forall_param_coverage_in_obj(boxed_arg.as_ref(), coverage_by_forall_param);
193            }
194        }
195        Obj::CartDim(cart_dim) => {
196            mark_forall_param_coverage_in_obj(cart_dim.set.as_ref(), coverage_by_forall_param);
197        }
198        Obj::Proj(proj) => {
199            mark_forall_param_coverage_in_obj(proj.set.as_ref(), coverage_by_forall_param);
200            mark_forall_param_coverage_in_obj(proj.dim.as_ref(), coverage_by_forall_param);
201        }
202        Obj::TupleDim(tuple_dim) => {
203            mark_forall_param_coverage_in_obj(tuple_dim.arg.as_ref(), coverage_by_forall_param);
204        }
205        Obj::Tuple(tuple_obj) => {
206            for boxed_arg in tuple_obj.args.iter() {
207                mark_forall_param_coverage_in_obj(boxed_arg.as_ref(), coverage_by_forall_param);
208            }
209        }
210        Obj::Count(count) => {
211            mark_forall_param_coverage_in_obj(count.set.as_ref(), coverage_by_forall_param);
212        }
213        Obj::Range(range) => {
214            mark_forall_param_coverage_in_obj(range.start.as_ref(), coverage_by_forall_param);
215            mark_forall_param_coverage_in_obj(range.end.as_ref(), coverage_by_forall_param);
216        }
217        Obj::ClosedRange(closed_range) => {
218            mark_forall_param_coverage_in_obj(
219                closed_range.start.as_ref(),
220                coverage_by_forall_param,
221            );
222            mark_forall_param_coverage_in_obj(closed_range.end.as_ref(), coverage_by_forall_param);
223        }
224        Obj::FiniteSeqSet(fs) => {
225            mark_forall_param_coverage_in_obj(fs.set.as_ref(), coverage_by_forall_param);
226            mark_forall_param_coverage_in_obj(fs.n.as_ref(), coverage_by_forall_param);
227        }
228        Obj::SeqSet(ss) => {
229            mark_forall_param_coverage_in_obj(ss.set.as_ref(), coverage_by_forall_param);
230        }
231        Obj::FiniteSeqListObj(v) => {
232            for o in v.objs.iter() {
233                mark_forall_param_coverage_in_obj(o.as_ref(), coverage_by_forall_param);
234            }
235        }
236        Obj::MatrixSet(ms) => {
237            mark_forall_param_coverage_in_obj(ms.set.as_ref(), coverage_by_forall_param);
238            mark_forall_param_coverage_in_obj(ms.row_len.as_ref(), coverage_by_forall_param);
239            mark_forall_param_coverage_in_obj(ms.col_len.as_ref(), coverage_by_forall_param);
240        }
241        Obj::MatrixListObj(v) => {
242            for row in v.rows.iter() {
243                for o in row.iter() {
244                    mark_forall_param_coverage_in_obj(o.as_ref(), coverage_by_forall_param);
245                }
246            }
247        }
248        Obj::Choose(choose) => {
249            mark_forall_param_coverage_in_obj(choose.set.as_ref(), coverage_by_forall_param);
250        }
251        Obj::ObjAtIndex(obj_at_index) => {
252            mark_forall_param_coverage_in_obj(obj_at_index.obj.as_ref(), coverage_by_forall_param);
253            mark_forall_param_coverage_in_obj(
254                obj_at_index.index.as_ref(),
255                coverage_by_forall_param,
256            );
257        }
258        Obj::FamilyObj(family) => {
259            for param_obj in family.params.iter() {
260                mark_forall_param_coverage_in_obj(param_obj, coverage_by_forall_param);
261            }
262        }
263        Obj::StructObj(struct_ty) => {
264            for param_obj in struct_ty.args.iter() {
265                mark_forall_param_coverage_in_obj(param_obj, coverage_by_forall_param);
266            }
267        }
268    }
269}
270
271fn mark_forall_param_coverage_in_atomic_fact(
272    atomic_fact: &AtomicFact,
273    coverage_by_forall_param: &mut HashMap<IdentifierName, bool>,
274) {
275    match atomic_fact {
276        AtomicFact::NormalAtomicFact(fact) => {
277            for body_obj in fact.body.iter() {
278                mark_forall_param_coverage_in_obj(body_obj, coverage_by_forall_param);
279            }
280        }
281        AtomicFact::NotNormalAtomicFact(fact) => {
282            for body_obj in fact.body.iter() {
283                mark_forall_param_coverage_in_obj(body_obj, coverage_by_forall_param);
284            }
285        }
286        AtomicFact::EqualFact(fact) => {
287            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
288            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
289        }
290        AtomicFact::LessFact(fact) => {
291            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
292            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
293        }
294        AtomicFact::GreaterFact(fact) => {
295            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
296            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
297        }
298        AtomicFact::LessEqualFact(fact) => {
299            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
300            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
301        }
302        AtomicFact::GreaterEqualFact(fact) => {
303            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
304            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
305        }
306        AtomicFact::NotEqualFact(fact) => {
307            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
308            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
309        }
310        AtomicFact::NotLessFact(fact) => {
311            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
312            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
313        }
314        AtomicFact::NotGreaterFact(fact) => {
315            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
316            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
317        }
318        AtomicFact::NotLessEqualFact(fact) => {
319            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
320            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
321        }
322        AtomicFact::NotGreaterEqualFact(fact) => {
323            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
324            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
325        }
326        AtomicFact::IsSetFact(fact) => {
327            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
328        }
329        AtomicFact::NotIsSetFact(fact) => {
330            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
331        }
332        AtomicFact::IsNonemptySetFact(fact) => {
333            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
334        }
335        AtomicFact::NotIsNonemptySetFact(fact) => {
336            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
337        }
338        AtomicFact::IsFiniteSetFact(fact) => {
339            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
340        }
341        AtomicFact::NotIsFiniteSetFact(fact) => {
342            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
343        }
344        AtomicFact::InFact(fact) => {
345            mark_forall_param_coverage_in_obj(&fact.element, coverage_by_forall_param);
346            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
347        }
348        AtomicFact::NotInFact(fact) => {
349            mark_forall_param_coverage_in_obj(&fact.element, coverage_by_forall_param);
350            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
351        }
352        AtomicFact::IsCartFact(fact) => {
353            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
354        }
355        AtomicFact::NotIsCartFact(fact) => {
356            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
357        }
358        AtomicFact::IsTupleFact(fact) => {
359            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
360        }
361        AtomicFact::NotIsTupleFact(fact) => {
362            mark_forall_param_coverage_in_obj(&fact.set, coverage_by_forall_param);
363        }
364        AtomicFact::SubsetFact(fact) => {
365            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
366            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
367        }
368        AtomicFact::SupersetFact(fact) => {
369            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
370            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
371        }
372        AtomicFact::NotSubsetFact(fact) => {
373            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
374            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
375        }
376        AtomicFact::NotSupersetFact(fact) => {
377            mark_forall_param_coverage_in_obj(&fact.left, coverage_by_forall_param);
378            mark_forall_param_coverage_in_obj(&fact.right, coverage_by_forall_param);
379        }
380        AtomicFact::RestrictFact(fact) => {
381            mark_forall_param_coverage_in_obj(&fact.obj, coverage_by_forall_param);
382            mark_forall_param_coverage_in_obj(
383                &fact.obj_can_restrict_to_fn_set,
384                coverage_by_forall_param,
385            );
386        }
387        AtomicFact::NotRestrictFact(fact) => {
388            mark_forall_param_coverage_in_obj(&fact.obj, coverage_by_forall_param);
389            mark_forall_param_coverage_in_obj(
390                &fact.obj_cannot_restrict_to_fn_set,
391                coverage_by_forall_param,
392            );
393        }
394    }
395}
396
397fn mark_forall_param_coverage_in_and_chain_atomic_fact(
398    parent_fact: &AndChainAtomicFact,
399    coverage_by_forall_param: &mut HashMap<IdentifierName, bool>,
400) {
401    match parent_fact {
402        AndChainAtomicFact::AtomicFact(atomic_fact) => {
403            mark_forall_param_coverage_in_atomic_fact(atomic_fact, coverage_by_forall_param);
404        }
405        AndChainAtomicFact::AndFact(and_fact) => {
406            for inner_atomic in and_fact.facts.iter() {
407                mark_forall_param_coverage_in_atomic_fact(inner_atomic, coverage_by_forall_param);
408            }
409        }
410        AndChainAtomicFact::ChainFact(chain_fact) => {
411            for chain_obj in chain_fact.objs.iter() {
412                mark_forall_param_coverage_in_obj(chain_obj, coverage_by_forall_param);
413            }
414        }
415    }
416}
417
418fn mark_forall_param_coverage_in_or_and_chain_atomic_fact(
419    parent_fact: &OrAndChainAtomicFact,
420    coverage_by_forall_param: &mut HashMap<IdentifierName, bool>,
421) {
422    match parent_fact {
423        OrAndChainAtomicFact::AtomicFact(atomic_fact) => {
424            mark_forall_param_coverage_in_atomic_fact(atomic_fact, coverage_by_forall_param);
425        }
426        OrAndChainAtomicFact::AndFact(and_fact) => {
427            for inner_atomic in and_fact.facts.iter() {
428                mark_forall_param_coverage_in_atomic_fact(inner_atomic, coverage_by_forall_param);
429            }
430        }
431        OrAndChainAtomicFact::ChainFact(chain_fact) => {
432            for chain_obj in chain_fact.objs.iter() {
433                mark_forall_param_coverage_in_obj(chain_obj, coverage_by_forall_param);
434            }
435        }
436        OrAndChainAtomicFact::OrFact(or_fact) => {
437            for branch in or_fact.facts.iter() {
438                mark_forall_param_coverage_in_and_chain_atomic_fact(
439                    branch,
440                    coverage_by_forall_param,
441                );
442            }
443        }
444    }
445}
446
447fn mark_forall_param_coverage_in_exist_fact(
448    exist_fact: &ExistFact,
449    coverage_by_forall_param: &mut HashMap<IdentifierName, bool>,
450) {
451    for param_def_with_type in exist_fact.params_def_with_type.groups.iter() {
452        mark_forall_param_coverage_in_param_type(
453            &param_def_with_type.param_type,
454            coverage_by_forall_param,
455        );
456    }
457    for inner_fact in exist_fact.facts.iter() {
458        mark_forall_param_coverage_in_or_and_chain_atomic_fact(
459            inner_fact,
460            coverage_by_forall_param,
461        );
462    }
463}
464
465fn mark_forall_param_coverage_in_exist_or_and_chain_atomic_fact(
466    parent_fact: &ExistOrAndChainAtomicFact,
467    coverage_by_forall_param: &mut HashMap<IdentifierName, bool>,
468) {
469    match parent_fact {
470        ExistOrAndChainAtomicFact::AtomicFact(atomic_fact) => {
471            mark_forall_param_coverage_in_atomic_fact(atomic_fact, coverage_by_forall_param);
472        }
473        ExistOrAndChainAtomicFact::AndFact(and_fact) => {
474            for inner_atomic in and_fact.facts.iter() {
475                mark_forall_param_coverage_in_atomic_fact(inner_atomic, coverage_by_forall_param);
476            }
477        }
478        ExistOrAndChainAtomicFact::ChainFact(chain_fact) => {
479            for chain_obj in chain_fact.objs.iter() {
480                mark_forall_param_coverage_in_obj(chain_obj, coverage_by_forall_param);
481            }
482        }
483        ExistOrAndChainAtomicFact::OrFact(or_fact) => {
484            for branch in or_fact.facts.iter() {
485                mark_forall_param_coverage_in_and_chain_atomic_fact(
486                    branch,
487                    coverage_by_forall_param,
488                );
489            }
490        }
491        ExistOrAndChainAtomicFact::ExistFact(exist_fact) => {
492            mark_forall_param_coverage_in_exist_fact(exist_fact, coverage_by_forall_param);
493        }
494    }
495}
496
497impl ForallFact {
498    pub fn error_messages_if_forall_param_missing_in_some_then_clause(
499        &self,
500    ) -> Vec<(usize, String)> {
501        let forall_param_names = self.params_def_with_type.collect_param_names();
502        if forall_param_names.is_empty() {
503            return Vec::new();
504        }
505        let mut error_messages = Vec::new();
506        let mut then_index: usize = 0;
507        while then_index < self.then_facts.len() {
508            let then_fact = &self.then_facts[then_index];
509            let mut coverage_by_forall_param: HashMap<IdentifierName, bool> = HashMap::new();
510            for param_name in forall_param_names.iter() {
511                coverage_by_forall_param.insert(param_name.clone(), false);
512            }
513            mark_forall_param_coverage_in_exist_or_and_chain_atomic_fact(
514                then_fact,
515                &mut coverage_by_forall_param,
516            );
517            let mut missing_param_names = Vec::new();
518            for param_name in forall_param_names.iter() {
519                let is_mentioned_in_then_clause = match coverage_by_forall_param.get(param_name) {
520                    Some(flag) => *flag,
521                    None => false,
522                };
523                if !is_mentioned_in_then_clause {
524                    missing_param_names.push(param_name.clone());
525                }
526            }
527            if !missing_param_names.is_empty() {
528                let missing_list = missing_param_names.join(", ");
529                error_messages.push((
530                    then_index,
531                    format!(
532                        "then-clause `{}` does not mention forall parameter(s) {{{}}}",
533                        then_fact, missing_list,
534                    ),
535                ));
536            }
537            then_index += 1;
538        }
539        error_messages
540    }
541}
542
543impl ForallFactWithIff {
544    /// Only checks the embedded [`ForallFact`]'s `then_facts` (not `iff_facts`).
545    pub fn error_messages_if_forall_param_missing_in_forall_then_clause(
546        &self,
547    ) -> Vec<(usize, String)> {
548        self.forall_fact
549            .error_messages_if_forall_param_missing_in_some_then_clause()
550    }
551}