1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use super::Validator;
use crate::diagnostics::Diagnostic;
use crate::evaluator_rules::Rule;
use crate::grammar::collectors::collect_var_asgns;
use crate::grammar::*;
use crate::partial_evaluator::compare::{cmp_eq, EqRelation};
use crate::ProgramContext;
use std::collections::{BTreeSet, HashMap};
static MAX_DEFINITION_PAIRS: usize = 100;
fn all_ordered_definition_pairs(
var_asgns: HashMap<InternedStr, Vec<&Assignment>>,
) -> Vec<(InternedStr, &Assignment, &Assignment)> {
let mut definition_pairs = Vec::new();
for (name, asgns) in var_asgns.into_iter() {
if asgns.len() < 2 {
continue;
}
if definition_pairs.len() > MAX_DEFINITION_PAIRS {
break;
}
let mut pairs = Vec::with_capacity((asgns.len() * asgns.len() - 1) / 2);
for i in 0..asgns.len() {
for j in i + 1..asgns.len() {
pairs.push((name, asgns[i], asgns[j]));
}
}
definition_pairs.extend(pairs);
}
while definition_pairs.len() > MAX_DEFINITION_PAIRS {
definition_pairs.pop();
}
definition_pairs.sort_by(|&(_, a, c), &(_, b, d)| {
if a.span == b.span {
c.span.cmp(&d.span)
} else {
a.span.cmp(&b.span)
}
});
definition_pairs
}
fn validate(
program: &StmtList,
context: &ProgramContext,
evaluator_rules: &[Rule],
) -> Vec<Diagnostic> {
let mut diagnostics = Vec::new();
let var_asgns = collect_var_asgns(&program);
let definition_pairs = all_ordered_definition_pairs(var_asgns);
for (name, def_a, def_b) in definition_pairs.into_iter() {
diagnostics.push(
match cmp_eq(&def_a.rhs, &def_b.rhs, evaluator_rules, context) {
EqRelation::AlwaysEquivalent => continue,
EqRelation::NeverEquivalent => IncompatibleDefinitions!(name, def_a, def_b),
EqRelation::DependsOn(_) if !context.lint => continue,
EqRelation::DependsOn(dep_vars) => {
let dep_vars = dep_vars
.into_iter()
.map(|v| v.to_string())
.collect::<BTreeSet<_>>();
MaybeIncompatibleDefinitions!(name, def_a, def_b, dep_vars)
}
},
);
}
diagnostics
}
pub(super) struct IncompatibleDefinitionsValidator;
impl<'a> Validator<'a> for IncompatibleDefinitionsValidator {
fn validate(
stmt_list: &StmtList,
_source: &'a str,
context: &ProgramContext,
evaluator_rules: &[Rule],
) -> Vec<Diagnostic> {
validate(stmt_list, context, evaluator_rules)
}
}