1use crate::{
18 ArrayType,
19 CompositeType,
20 FutureType,
21 Identifier,
22 IntegerType,
23 Location,
24 MappingType,
25 OptionalType,
26 Path,
27 ProgramId,
28 TupleType,
29 Type,
30 TypeInterner,
31 VectorType,
32};
33
34use itertools::Itertools;
35use leo_span::Span;
36use serde::Serialize;
37use snarkvm::prelude::{
38 LiteralType,
39 Network,
40 PlaintextType,
41 PlaintextType::{Array, ExternalStruct, Literal, Struct},
42};
43use std::fmt;
44
45#[derive(Clone, Debug, Eq, Serialize)]
49pub struct TypeNode {
50 kind: TypeKind,
51 pub span: Span,
52 #[serde(skip)]
53 type_: Type,
54}
55
56impl TypeNode {
57 pub fn new(interner: &TypeInterner, kind: TypeKind, span: Span) -> Self {
58 let type_ = interner.intern(&kind);
59 Self { kind, span, type_ }
60 }
61
62 pub fn unchecked(kind: TypeKind, span: Span) -> Self {
65 Self { kind, span, type_: Type::default() }
66 }
67
68 pub fn kind(&self) -> &TypeKind {
69 &self.kind
70 }
71
72 pub fn ty(&self) -> Type {
73 self.type_
74 }
75
76 pub fn into_parts(self) -> (TypeKind, Span, Type) {
77 (self.kind, self.span, self.type_)
78 }
79
80 pub fn from_parts(kind: TypeKind, span: Span, type_: Type) -> Self {
83 Self { kind, span, type_ }
84 }
85
86 pub fn types_equivalent(&self, other: &TypeNode) -> bool {
90 if self.type_ != Type::ERR && self.type_ == other.type_ {
91 return true;
92 }
93 self.kind.types_equivalent(&other.kind)
94 }
95}
96
97impl Default for TypeNode {
98 fn default() -> Self {
99 Self::unchecked(TypeKind::Err, Span::default())
100 }
101}
102
103impl PartialEq for TypeNode {
104 fn eq(&self, other: &Self) -> bool {
105 assert!(
106 self.kind == TypeKind::Err || self.type_ != Type::ERR,
107 "TypeNode with non-Err kind must have been interned before equality use",
108 );
109 assert!(
110 other.kind == TypeKind::Err || other.type_ != Type::ERR,
111 "TypeNode with non-Err kind must have been interned before equality use",
112 );
113 self.type_ == other.type_
114 }
115}
116
117impl std::hash::Hash for TypeNode {
118 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
119 assert!(
120 self.kind == TypeKind::Err || self.type_ != Type::ERR,
121 "TypeNode with non-Err kind must have been interned before hashing",
122 );
123 self.type_.hash(state);
124 }
125}
126
127impl fmt::Display for TypeNode {
128 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129 self.kind.fmt(f)
130 }
131}
132
133#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Serialize)]
135pub enum TypeKind {
136 Address,
138 Array(ArrayType),
140 Boolean,
142 Composite(CompositeType),
144 Field,
146 Future(FutureType),
148 Group,
150 Identifier,
152 DynRecord,
154 Ident(Identifier),
156 Integer(IntegerType),
158 Mapping(MappingType),
160 Optional(OptionalType),
162 Scalar,
164 Signature,
166 String,
168 Tuple(TupleType),
170 Vector(VectorType),
172 Numeric,
174 Unit,
176 #[default]
179 Err,
180}
181
182impl TypeKind {
183 pub fn types_equivalent(&self, other: &TypeKind) -> bool {
196 match (self, other) {
197 (TypeKind::Err, _)
198 | (_, TypeKind::Err)
199 | (TypeKind::Address, TypeKind::Address)
200 | (TypeKind::Boolean, TypeKind::Boolean)
201 | (TypeKind::Field, TypeKind::Field)
202 | (TypeKind::Group, TypeKind::Group)
203 | (TypeKind::Scalar, TypeKind::Scalar)
204 | (TypeKind::Signature, TypeKind::Signature)
205 | (TypeKind::String, TypeKind::String)
206 | (TypeKind::Identifier, TypeKind::Identifier)
207 | (TypeKind::DynRecord, TypeKind::DynRecord)
208 | (TypeKind::Unit, TypeKind::Unit) => true,
209 (TypeKind::Array(left), TypeKind::Array(right)) => {
210 (match (left.length.as_u32(), right.length.as_u32()) {
211 (Some(l1), Some(l2)) => l1 == l2,
212 _ => {
213 true
216 }
217 }) && left.element_type().types_equivalent(right.element_type())
218 }
219 (TypeKind::Ident(left), TypeKind::Ident(right)) => left.name == right.name,
220 (TypeKind::Integer(left), TypeKind::Integer(right)) => left == right,
221 (TypeKind::Mapping(left), TypeKind::Mapping(right)) => {
222 left.key.types_equivalent(&right.key) && left.value.types_equivalent(&right.value)
223 }
224 (TypeKind::Optional(left), TypeKind::Optional(right)) => left.inner.types_equivalent(&right.inner),
225 (TypeKind::Tuple(left), TypeKind::Tuple(right)) if left.length() == right.length() => left
226 .elements()
227 .iter()
228 .zip_eq(right.elements().iter())
229 .all(|(left_type, right_type)| left_type.types_equivalent(right_type)),
230 (TypeKind::Vector(left), TypeKind::Vector(right)) => {
231 left.element_type.types_equivalent(&right.element_type)
232 }
233 (TypeKind::Composite(left), TypeKind::Composite(right)) => {
234 if !left.const_arguments.is_empty() || !right.const_arguments.is_empty() {
237 return true;
238 }
239
240 match (&left.path.try_global_location(), &right.path.try_global_location()) {
242 (Some(l), Some(r)) => l == r,
243 _ => false,
244 }
245 }
246
247 (TypeKind::Future(left), TypeKind::Future(right)) if !left.is_explicit || !right.is_explicit => true,
248 (TypeKind::Future(left), TypeKind::Future(right)) if left.inputs.len() == right.inputs.len() => left
249 .inputs()
250 .iter()
251 .zip_eq(right.inputs().iter())
252 .all(|(left_type, right_type)| left_type.types_equivalent(right_type)),
253 _ => false,
254 }
255 }
256
257 pub fn from_snarkvm<N: Network>(t: &PlaintextType<N>, program_id: ProgramId) -> Self {
258 match t {
259 Literal(lit) => (*lit).into(),
260 Struct(s) => TypeKind::Composite(CompositeType {
261 path: {
262 let ident = Identifier::from(s);
263 Path::from(ident).to_global(Location::new(program_id.as_symbol(), vec![ident.name]))
264 },
265 const_arguments: Vec::new(),
266 }),
267 ExternalStruct(l) => TypeKind::Composite(CompositeType {
268 path: {
269 let external_program = ProgramId::from(l.program_id());
270 let name = Identifier::from(l.resource());
271 Path::from(name)
272 .with_user_program(external_program)
273 .to_global(Location::new(external_program.as_symbol(), vec![name.name]))
274 },
275 const_arguments: Vec::new(),
276 }),
277 Array(array) => TypeKind::Array(ArrayType::from_snarkvm(array, program_id)),
278 }
279 }
280
281 pub fn to_snarkvm<N: Network>(&self) -> anyhow::Result<PlaintextType<N>> {
283 match self {
284 TypeKind::Address => Ok(PlaintextType::Literal(snarkvm::prelude::LiteralType::Address)),
285 TypeKind::Boolean => Ok(PlaintextType::Literal(snarkvm::prelude::LiteralType::Boolean)),
286 TypeKind::Field => Ok(PlaintextType::Literal(snarkvm::prelude::LiteralType::Field)),
287 TypeKind::Group => Ok(PlaintextType::Literal(snarkvm::prelude::LiteralType::Group)),
288 TypeKind::Integer(int_type) => match int_type {
289 IntegerType::U8 => Ok(PlaintextType::Literal(snarkvm::prelude::LiteralType::U8)),
290 IntegerType::U16 => Ok(PlaintextType::Literal(snarkvm::prelude::LiteralType::U16)),
291 IntegerType::U32 => Ok(PlaintextType::Literal(snarkvm::prelude::LiteralType::U32)),
292 IntegerType::U64 => Ok(PlaintextType::Literal(snarkvm::prelude::LiteralType::U64)),
293 IntegerType::U128 => Ok(PlaintextType::Literal(snarkvm::prelude::LiteralType::U128)),
294 IntegerType::I8 => Ok(PlaintextType::Literal(snarkvm::prelude::LiteralType::I8)),
295 IntegerType::I16 => Ok(PlaintextType::Literal(snarkvm::prelude::LiteralType::I16)),
296 IntegerType::I32 => Ok(PlaintextType::Literal(snarkvm::prelude::LiteralType::I32)),
297 IntegerType::I64 => Ok(PlaintextType::Literal(snarkvm::prelude::LiteralType::I64)),
298 IntegerType::I128 => Ok(PlaintextType::Literal(snarkvm::prelude::LiteralType::I128)),
299 },
300 TypeKind::Scalar => Ok(PlaintextType::Literal(snarkvm::prelude::LiteralType::Scalar)),
301 TypeKind::Signature => Ok(PlaintextType::Literal(snarkvm::prelude::LiteralType::Signature)),
302 TypeKind::Array(array_type) => Ok(PlaintextType::<N>::Array(array_type.to_snarkvm()?)),
303 _ => anyhow::bail!("Converting from type {self} to snarkVM type is not supported"),
304 }
305 }
306
307 pub fn size_in_bits<N: Network, F0, F1>(
309 &self,
310 is_raw: bool,
311 get_structs: F0,
312 get_external_structs: F1,
313 ) -> anyhow::Result<usize>
314 where
315 F0: Fn(&snarkvm::prelude::Identifier<N>) -> anyhow::Result<snarkvm::prelude::StructType<N>>,
316 F1: Fn(&snarkvm::prelude::Locator<N>) -> anyhow::Result<snarkvm::prelude::StructType<N>>,
317 {
318 match is_raw {
319 false => self.to_snarkvm::<N>()?.size_in_bits(&get_structs, &get_external_structs),
320 true => self.to_snarkvm::<N>()?.size_in_bits_raw(&get_structs, &get_external_structs),
321 }
322 }
323
324 pub fn can_coerce_to(&self, expected: &TypeKind) -> bool {
340 use TypeKind::*;
341
342 match (self, expected) {
343 (Optional(actual_opt), Optional(expected_opt)) => actual_opt.inner.can_coerce_to(&expected_opt.inner),
345
346 (a, Optional(opt)) => a.can_coerce_to(&opt.inner),
348
349 (Array(a_arr), Array(e_arr)) => {
351 let lengths_equal = match (a_arr.length.as_u32(), e_arr.length.as_u32()) {
352 (Some(l1), Some(l2)) => l1 == l2,
353 _ => true,
354 };
355
356 lengths_equal && a_arr.element_type().can_coerce_to(e_arr.element_type())
357 }
358
359 _ => self.types_equivalent(expected),
361 }
362 }
363
364 pub fn is_optional(&self) -> bool {
365 matches!(self, Self::Optional(_))
366 }
367
368 pub fn is_vector(&self) -> bool {
369 matches!(self, Self::Vector(_))
370 }
371
372 pub fn is_mapping(&self) -> bool {
373 matches!(self, Self::Mapping(_))
374 }
375
376 pub fn to_optional(&self) -> TypeKind {
377 TypeKind::Optional(OptionalType { inner: Box::new(self.clone()) })
378 }
379
380 pub fn is_empty(&self) -> bool {
381 match self {
382 TypeKind::Unit => true,
383 TypeKind::Array(array_type) => {
384 if let Some(length) = array_type.length.as_u32() {
385 length == 0
386 } else {
387 false
388 }
389 }
390 _ => false,
391 }
392 }
393
394 pub fn is_valid_const_generic_type(&self) -> bool {
398 matches!(
399 self,
400 TypeKind::Boolean
401 | TypeKind::Integer(_)
402 | TypeKind::Address
403 | TypeKind::Scalar
404 | TypeKind::Group
405 | TypeKind::Field
406 | TypeKind::Identifier
407 )
408 }
409}
410
411impl From<LiteralType> for TypeKind {
412 fn from(value: LiteralType) -> Self {
413 match value {
414 LiteralType::Identifier => TypeKind::Identifier,
415 LiteralType::Address => TypeKind::Address,
416 LiteralType::Boolean => TypeKind::Boolean,
417 LiteralType::Field => TypeKind::Field,
418 LiteralType::Group => TypeKind::Group,
419 LiteralType::U8 => TypeKind::Integer(IntegerType::U8),
420 LiteralType::U16 => TypeKind::Integer(IntegerType::U16),
421 LiteralType::U32 => TypeKind::Integer(IntegerType::U32),
422 LiteralType::U64 => TypeKind::Integer(IntegerType::U64),
423 LiteralType::U128 => TypeKind::Integer(IntegerType::U128),
424 LiteralType::I8 => TypeKind::Integer(IntegerType::I8),
425 LiteralType::I16 => TypeKind::Integer(IntegerType::I16),
426 LiteralType::I32 => TypeKind::Integer(IntegerType::I32),
427 LiteralType::I64 => TypeKind::Integer(IntegerType::I64),
428 LiteralType::I128 => TypeKind::Integer(IntegerType::I128),
429 LiteralType::Scalar => TypeKind::Scalar,
430 LiteralType::Signature => TypeKind::Signature,
431 LiteralType::String => TypeKind::String,
432 }
433 }
434}
435
436impl fmt::Display for TypeKind {
437 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
438 match *self {
439 TypeKind::Address => write!(f, "address"),
440 TypeKind::Identifier => write!(f, "identifier"),
441 TypeKind::DynRecord => write!(f, "dyn record"),
442 TypeKind::Array(ref array_type) => write!(f, "{array_type}"),
443 TypeKind::Boolean => write!(f, "bool"),
444 TypeKind::Field => write!(f, "field"),
445 TypeKind::Future(ref future_type) => write!(f, "{future_type}"),
446 TypeKind::Group => write!(f, "group"),
447 TypeKind::Ident(ref variable) => write!(f, "{variable}"),
448 TypeKind::Integer(ref integer_type) => write!(f, "{integer_type}"),
449 TypeKind::Mapping(ref mapping_type) => write!(f, "{mapping_type}"),
450 TypeKind::Optional(ref optional_type) => write!(f, "{optional_type}"),
451 TypeKind::Scalar => write!(f, "scalar"),
452 TypeKind::Signature => write!(f, "signature"),
453 TypeKind::String => write!(f, "string"),
454 TypeKind::Composite(ref composite_type) => write!(f, "{composite_type}"),
455 TypeKind::Tuple(ref tuple) => write!(f, "{tuple}"),
456 TypeKind::Vector(ref vector_type) => write!(f, "{vector_type}"),
457 TypeKind::Numeric => write!(f, "numeric"),
458 TypeKind::Unit => write!(f, "()"),
459 TypeKind::Err => write!(f, "error"),
460 }
461 }
462}
463
464#[cfg(test)]
465mod tests {
466 use super::*;
467
468 #[test]
469 #[should_panic(expected = "TypeNode with non-Err kind must have been interned")]
470 fn eq_panics_on_unchecked_non_err_kind() {
471 let interner = TypeInterner::new();
472 let unchecked = TypeNode::unchecked(TypeKind::Address, Span::default());
473 let interned = TypeNode::new(&interner, TypeKind::Boolean, Span::default());
474 let _ = unchecked == interned;
475 }
476
477 #[test]
478 #[should_panic(expected = "TypeNode with non-Err kind must have been interned")]
479 fn hash_panics_on_unchecked_non_err_kind() {
480 use std::hash::Hash;
481
482 let unchecked = TypeNode::unchecked(TypeKind::Address, Span::default());
483 let mut hasher = std::collections::hash_map::DefaultHasher::new();
484 unchecked.hash(&mut hasher);
485 }
486
487 #[test]
488 fn eq_accepts_defaulted_err_nodes() {
489 let a = TypeNode::default();
492 let b = TypeNode::default();
493 assert_eq!(a, b);
494 }
495}