1use crate::{
18 ArrayType,
19 CompositeType,
20 FutureType,
21 Identifier,
22 IntegerType,
23 MappingType,
24 OptionalType,
25 Path,
26 TupleType,
27};
28
29use itertools::Itertools;
30use leo_span::Symbol;
31use serde::{Deserialize, Serialize};
32use snarkvm::prelude::{
33 Network,
34 PlaintextType,
35 PlaintextType::{Array, Literal, Struct},
36};
37use std::fmt;
38
39#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
41pub enum Type {
42 Address,
44 Array(ArrayType),
46 Boolean,
48 Composite(CompositeType),
50 Field,
52 Future(FutureType),
54 Group,
56 Identifier(Identifier),
58 Integer(IntegerType),
60 Mapping(MappingType),
62 Optional(OptionalType),
64 Scalar,
66 Signature,
68 String,
70 Tuple(TupleType),
72 Numeric,
74 Unit,
76 #[default]
79 Err,
80}
81
82impl Type {
83 pub fn eq_user(&self, other: &Type) -> bool {
96 match (self, other) {
97 (Type::Err, _)
98 | (_, Type::Err)
99 | (Type::Address, Type::Address)
100 | (Type::Boolean, Type::Boolean)
101 | (Type::Field, Type::Field)
102 | (Type::Group, Type::Group)
103 | (Type::Scalar, Type::Scalar)
104 | (Type::Signature, Type::Signature)
105 | (Type::String, Type::String)
106 | (Type::Unit, Type::Unit) => true,
107 (Type::Array(left), Type::Array(right)) => {
108 (match (left.length.as_u32(), right.length.as_u32()) {
109 (Some(l1), Some(l2)) => l1 == l2,
110 _ => {
111 true
114 }
115 }) && left.element_type().eq_user(right.element_type())
116 }
117 (Type::Identifier(left), Type::Identifier(right)) => left.name == right.name,
118 (Type::Integer(left), Type::Integer(right)) => left == right,
119 (Type::Mapping(left), Type::Mapping(right)) => {
120 left.key.eq_user(&right.key) && left.value.eq_user(&right.value)
121 }
122 (Type::Optional(left), Type::Optional(right)) => left.inner.eq_user(&right.inner),
123 (Type::Tuple(left), Type::Tuple(right)) if left.length() == right.length() => left
124 .elements()
125 .iter()
126 .zip_eq(right.elements().iter())
127 .all(|(left_type, right_type)| left_type.eq_user(right_type)),
128 (Type::Composite(left), Type::Composite(right)) => {
129 if !left.const_arguments.is_empty() || !right.const_arguments.is_empty() {
132 return true;
133 }
134
135 (left.program == right.program)
137 && match (&left.path.try_absolute_path(), &right.path.try_absolute_path()) {
138 (Some(l), Some(r)) => l == r,
139 _ => false,
140 }
141 }
142 (Type::Future(left), Type::Future(right)) if !left.is_explicit || !right.is_explicit => true,
143 (Type::Future(left), Type::Future(right)) if left.inputs.len() == right.inputs.len() => left
144 .inputs()
145 .iter()
146 .zip_eq(right.inputs().iter())
147 .all(|(left_type, right_type)| left_type.eq_user(right_type)),
148 _ => false,
149 }
150 }
151
152 pub fn eq_flat_relaxed(&self, other: &Self) -> bool {
162 match (self, other) {
163 (Type::Address, Type::Address)
164 | (Type::Boolean, Type::Boolean)
165 | (Type::Field, Type::Field)
166 | (Type::Group, Type::Group)
167 | (Type::Scalar, Type::Scalar)
168 | (Type::Signature, Type::Signature)
169 | (Type::String, Type::String)
170 | (Type::Unit, Type::Unit) => true,
171 (Type::Array(left), Type::Array(right)) => {
172 (match (left.length.as_u32(), right.length.as_u32()) {
175 (Some(l1), Some(l2)) => l1 == l2,
176 _ => {
177 true
180 }
181 }) && left.element_type().eq_flat_relaxed(right.element_type())
182 }
183 (Type::Identifier(left), Type::Identifier(right)) => left.matches(right),
184 (Type::Integer(left), Type::Integer(right)) => left.eq(right),
185 (Type::Mapping(left), Type::Mapping(right)) => {
186 left.key.eq_flat_relaxed(&right.key) && left.value.eq_flat_relaxed(&right.value)
187 }
188 (Type::Optional(left), Type::Optional(right)) => left.inner.eq_flat_relaxed(&right.inner),
189 (Type::Tuple(left), Type::Tuple(right)) if left.length() == right.length() => left
190 .elements()
191 .iter()
192 .zip_eq(right.elements().iter())
193 .all(|(left_type, right_type)| left_type.eq_flat_relaxed(right_type)),
194 (Type::Composite(left), Type::Composite(right)) => {
195 if !left.const_arguments.is_empty() || !right.const_arguments.is_empty() {
198 return true;
199 }
200
201 match (&left.path.try_absolute_path(), &right.path.try_absolute_path()) {
205 (Some(l), Some(r)) => l == r,
206 _ => false,
207 }
208 }
209 (Type::Future(left), Type::Future(right)) if !left.is_explicit || !right.is_explicit => true,
211 (Type::Future(left), Type::Future(right)) if left.inputs.len() == right.inputs.len() => left
212 .inputs()
213 .iter()
214 .zip_eq(right.inputs().iter())
215 .all(|(left_type, right_type)| left_type.eq_flat_relaxed(right_type)),
216 _ => false,
217 }
218 }
219
220 pub fn from_snarkvm<N: Network>(t: &PlaintextType<N>, program: Option<Symbol>) -> Self {
221 match t {
222 Literal(lit) => match lit {
223 snarkvm::prelude::LiteralType::Address => Type::Address,
224 snarkvm::prelude::LiteralType::Boolean => Type::Boolean,
225 snarkvm::prelude::LiteralType::Field => Type::Field,
226 snarkvm::prelude::LiteralType::Group => Type::Group,
227 snarkvm::prelude::LiteralType::U8 => Type::Integer(IntegerType::U8),
228 snarkvm::prelude::LiteralType::U16 => Type::Integer(IntegerType::U16),
229 snarkvm::prelude::LiteralType::U32 => Type::Integer(IntegerType::U32),
230 snarkvm::prelude::LiteralType::U64 => Type::Integer(IntegerType::U64),
231 snarkvm::prelude::LiteralType::U128 => Type::Integer(IntegerType::U128),
232 snarkvm::prelude::LiteralType::I8 => Type::Integer(IntegerType::I8),
233 snarkvm::prelude::LiteralType::I16 => Type::Integer(IntegerType::I16),
234 snarkvm::prelude::LiteralType::I32 => Type::Integer(IntegerType::I32),
235 snarkvm::prelude::LiteralType::I64 => Type::Integer(IntegerType::I64),
236 snarkvm::prelude::LiteralType::I128 => Type::Integer(IntegerType::I128),
237 snarkvm::prelude::LiteralType::Scalar => Type::Scalar,
238 snarkvm::prelude::LiteralType::Signature => Type::Signature,
239 snarkvm::prelude::LiteralType::String => Type::String,
240 },
241 Struct(s) => Type::Composite(CompositeType {
242 path: {
243 let ident = Identifier::from(s);
244 Path::from(ident).with_absolute_path(Some(vec![ident.name]))
245 },
246 const_arguments: Vec::new(),
247 program,
248 }),
249 Array(array) => Type::Array(ArrayType::from_snarkvm(array, program)),
250 }
251 }
252
253 pub fn can_coerce_to(&self, expected: &Type) -> bool {
269 use Type::*;
270
271 match (self, expected) {
272 (Optional(actual_opt), Optional(expected_opt)) => actual_opt.inner.can_coerce_to(&expected_opt.inner),
274
275 (a, Optional(opt)) => a.can_coerce_to(&opt.inner),
277
278 (Array(a_arr), Array(e_arr)) => {
280 let lengths_equal = match (a_arr.length.as_u32(), e_arr.length.as_u32()) {
281 (Some(l1), Some(l2)) => l1 == l2,
282 _ => true,
283 };
284
285 lengths_equal && a_arr.element_type().can_coerce_to(e_arr.element_type())
286 }
287
288 _ => self.eq_user(expected),
290 }
291 }
292}
293
294impl fmt::Display for Type {
295 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
296 match *self {
297 Type::Address => write!(f, "address"),
298 Type::Array(ref array_type) => write!(f, "{array_type}"),
299 Type::Boolean => write!(f, "bool"),
300 Type::Field => write!(f, "field"),
301 Type::Future(ref future_type) => write!(f, "{future_type}"),
302 Type::Group => write!(f, "group"),
303 Type::Identifier(ref variable) => write!(f, "{variable}"),
304 Type::Integer(ref integer_type) => write!(f, "{integer_type}"),
305 Type::Mapping(ref mapping_type) => write!(f, "{mapping_type}"),
306 Type::Optional(ref optional_type) => write!(f, "{optional_type}"),
307 Type::Scalar => write!(f, "scalar"),
308 Type::Signature => write!(f, "signature"),
309 Type::String => write!(f, "string"),
310 Type::Composite(ref struct_type) => write!(f, "{struct_type}"),
311 Type::Tuple(ref tuple) => write!(f, "{tuple}"),
312 Type::Numeric => write!(f, "numeric"),
313 Type::Unit => write!(f, "()"),
314 Type::Err => write!(f, "error"),
315 }
316 }
317}