verilization_compiler/
type_check.rs1use crate::model::*;
2use num_bigint::BigUint;
3use num_traits::One;
4use std::collections::HashSet;
5
6#[derive(Debug)]
7pub enum TypeCheckError {
8 TypeNotDefined(QualifiedName),
9 TypeAddedInNewerVersion(QualifiedName, BigUint),
10 CouldNotFindLastVersion(QualifiedName),
11 ArityMismatch(usize, usize),
12 TypeNotFinal(QualifiedName),
13 DuplicateLiteral(QualifiedName),
14}
15
16struct TypeCheck<'model> {
17 model: &'model Verilization,
18 scope: Scope<'model>,
19}
20
21impl <'model> TypeCheck<'model> {
22
23 fn check_type(&self, version: &BigUint, t: &Type) -> Result<(), TypeCheckError> {
24 match self.scope.lookup(t.name.clone()) {
25 ScopeLookup::NamedType(name) => {
26 let named_type_def = match self.model.get_type(&name) {
27 Some(t) => t,
28 None => return Err(TypeCheckError::TypeNotDefined(name)),
29 };
30
31 if !named_type_def.has_version(version) {
32 return Err(TypeCheckError::TypeAddedInNewerVersion(name, version.clone()));
33 }
34
35 let arity = named_type_def.arity();
36 if arity != t.args.len() {
37 return Err(TypeCheckError::ArityMismatch(arity, t.args.len()));
38 }
39
40 for arg in &t.args {
41 self.check_type(version, &arg)?;
42 }
43
44 Ok(())
45 },
46 ScopeLookup::TypeParameter(_) => {
47 if t.args.len() != 0 {
48 return Err(TypeCheckError::ArityMismatch(0, t.args.len()));
49 }
50
51 Ok(())
52 }
53 }
54 }
55
56 fn check_is_final(&self, t: &Type, version: &BigUint) -> Result<bool, TypeCheckError> {
57 Ok(match self.scope.lookup(t.name.clone()) {
58 ScopeLookup::NamedType(name) => {
59 match self.model.get_type(&name).ok_or_else(|| TypeCheckError::TypeNotDefined(name.clone()))? {
60 NamedTypeDefinition::StructType(type_def) | NamedTypeDefinition::EnumType(type_def) => {
61 if !type_def.is_final() {
62 return Ok(false);
63 }
64
65 if !(type_def.last_explicit_version().ok_or_else(|| TypeCheckError::CouldNotFindLastVersion(name.clone()))? <= version) {
66 return Ok(false);
67 }
68 },
69
70 NamedTypeDefinition::ExternType(_) => (),
71 }
72
73 for arg in &t.args {
74 if !self.check_is_final(&arg, version)? {
75 return Ok(false);
76 }
77 }
78
79 true
80 },
81 ScopeLookup::TypeParameter(_) => true,
82 })
83 }
84
85}
86
87fn type_check_versioned_type<'model>(model: &'model Verilization, t: Named<'model, VersionedTypeDefinitionData>) -> Result<(), TypeCheckError> {
88 let tc = TypeCheck {
89 model: model,
90 scope: t.scope(),
91 };
92
93 for ver in t.versions() {
94 for (_, field) in ver.ver_type.fields() {
95 tc.check_type(&ver.version, &field.field_type)?;
96 }
97 }
98
99 if t.is_final() {
100 if let Some(last_ver) = t.versions().last() {
101 for (_, field) in last_ver.ver_type.fields() {
102 if !tc.check_is_final(&field.field_type, &last_ver.version)? {
103 return Err(TypeCheckError::TypeNotFinal(t.name().clone()))
104 }
105 }
106 }
107 }
108
109 Ok(())
110}
111
112fn type_check_extern_type<'model>(model: &'model Verilization, t: Named<'model, ExternTypeDefinitionData>) -> Result<(), TypeCheckError> {
113 let tc = TypeCheck {
114 model: model,
115 scope: t.scope(),
116 };
117
118 let mut has_integer = false;
119 let mut has_string = false;
120 let mut has_sequence = false;
121 let mut literal_cases = HashSet::new();
122 let mut has_record = false;
123
124 for literal in t.literals() {
125 match literal {
126 ExternLiteralSpecifier::Integer(_, _, _, _) if has_integer => return Err(TypeCheckError::DuplicateLiteral(t.name().clone())),
127 ExternLiteralSpecifier::Integer(_, _, _, _) => has_integer = true,
128 ExternLiteralSpecifier::String if has_string => return Err(TypeCheckError::DuplicateLiteral(t.name().clone())),
129 ExternLiteralSpecifier::String => has_string = true,
130 ExternLiteralSpecifier::Sequence(_) if has_sequence => return Err(TypeCheckError::DuplicateLiteral(t.name().clone())),
131 ExternLiteralSpecifier::Sequence(inner) => {
132 has_sequence = true;
133 tc.check_type(&BigUint::one(), inner)?;
134 },
135 ExternLiteralSpecifier::Case(name, params) => {
136 if !literal_cases.insert(name) {
137 return Err(TypeCheckError::DuplicateLiteral(t.name().clone()));
138 }
139
140 for param in params {
141 tc.check_type(&BigUint::one(), param)?;
142 }
143 },
144 ExternLiteralSpecifier::Record(_) if has_record => return Err(TypeCheckError::DuplicateLiteral(t.name().clone())),
145 ExternLiteralSpecifier::Record(fields) => {
146 has_record = true;
147 for (_, field) in fields {
148 tc.check_type(&BigUint::one(), &field.field_type)?;
149 }
150 },
151 }
152 }
153
154 Ok(())
155}
156
157pub fn type_check_verilization(model: &Verilization) -> Result<(), TypeCheckError> {
158
159 for t in model.types() {
160 match t {
161 NamedTypeDefinition::StructType(t) | NamedTypeDefinition::EnumType(t) => type_check_versioned_type(model, t)?,
162 NamedTypeDefinition::ExternType(t) => type_check_extern_type(model, t)?,
163 }
164 }
165
166 Ok(())
167}
168
169