swamp_types/
calc_compat.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use crate::Type;
6use crate::cache::TypeCache;
7use crate::type_kind::TypeKind;
8
9impl Type {
10    pub(crate) fn do_compatible_with(&self, other: &Self, type_cache: &mut TypeCache) -> bool {
11        if self.id == other.id {
12            return true;
13        }
14
15        match (&*self.kind, &*other.kind) {
16            // Direct comparisons for primitive types
17            (TypeKind::Int, TypeKind::Int) => true,
18            (TypeKind::Float, TypeKind::Float) => true,
19            (TypeKind::Bool, TypeKind::Bool) => true,
20            (TypeKind::String, TypeKind::String) => true,
21            (TypeKind::Unit, TypeKind::Unit) => true,
22
23            // For container types, we compare their structure but delegate inner compatibility
24            // checks to TypeCache.compatible_with
25            (TypeKind::Optional(a), TypeKind::Optional(b)) => true,
26
27            (TypeKind::VecStorage(a, cap_a), TypeKind::VecStorage(b, cap_b)) => {
28                type_cache.compatible_with(a, b)
29            }
30            (TypeKind::SparseStorage(a, cap_a), TypeKind::SparseStorage(b, cap_b)) => {
31                type_cache.compatible_with(a, b)
32            }
33            (TypeKind::QueueStorage(a, cap_a), TypeKind::QueueStorage(b, cap_b)) => {
34                type_cache.compatible_with(a, b)
35            }
36
37            (TypeKind::StackStorage(a, cap_a), TypeKind::StackStorage(b, cap_b)) => {
38                type_cache.compatible_with(a, b)
39            }
40
41            (
42                TypeKind::MapStorage(a_key, a_value, cap_a),
43                TypeKind::MapStorage(b_key, b_value, cap_b),
44            ) => {
45                type_cache.compatible_with(a_key, b_key)
46                    && type_cache.compatible_with(a_value, b_value)
47            }
48
49            (
50                TypeKind::GridStorage(a, rows_a, cols_a),
51                TypeKind::GridStorage(b, rows_b, cols_b),
52            ) => rows_a >= rows_b && cols_a >= cols_b && type_cache.compatible_with(a, b),
53
54            (TypeKind::SliceView(a), TypeKind::SliceView(b)) => type_cache.compatible_with(a, b),
55            (TypeKind::SparseView(a), TypeKind::SparseView(b)) => type_cache.compatible_with(a, b),
56            (TypeKind::QueueView(a), TypeKind::QueueView(b)) => type_cache.compatible_with(a, b),
57            (TypeKind::StackView(a), TypeKind::StackView(b)) => type_cache.compatible_with(a, b),
58            (TypeKind::DynamicLengthVecView(a), TypeKind::DynamicLengthVecView(b)) => {
59                type_cache.compatible_with(a, b)
60            }
61            (
62                TypeKind::DynamicLengthMapView(a_key, a_value),
63                TypeKind::DynamicLengthMapView(b_key, b_value),
64            ) => {
65                type_cache.compatible_with(a_key, b_key)
66                    && type_cache.compatible_with(a_value, b_value)
67            }
68
69            (
70                TypeKind::FixedCapacityAndLengthArray(a, size_a),
71                TypeKind::FixedCapacityAndLengthArray(b, size_b),
72            ) => {
73                size_a == size_b && type_cache.compatible_with(a, b) // Fixed arrays must have the same size
74            }
75
76            (TypeKind::Tuple(elems_a), TypeKind::Tuple(elems_b)) => {
77                elems_a.len() == elems_b.len() // Tuples must have same length
78            }
79
80            (TypeKind::AnonymousStruct(anon_a), TypeKind::AnonymousStruct(anon_b)) => {
81                anon_a.field_name_sorted_fields.len() == anon_b.field_name_sorted_fields.len()
82                    && anon_a
83                        .field_name_sorted_fields
84                        .keys()
85                        .all(|key| anon_b.field_name_sorted_fields.contains_key(key))
86            }
87
88            (TypeKind::NamedStruct(named_a), TypeKind::NamedStruct(named_b)) => {
89                named_a.assigned_name == named_b.assigned_name
90                    && named_a.instantiated_type_parameters.len()
91                        == named_b.instantiated_type_parameters.len()
92            }
93
94            (TypeKind::Enum(enum_a), TypeKind::Enum(enum_b)) => {
95                enum_a.assigned_name == enum_b.assigned_name
96                    && enum_a.instantiated_type_parameters.len()
97                        == enum_b.instantiated_type_parameters.len()
98            }
99
100            (TypeKind::Function(sig_a), TypeKind::Function(sig_b)) => {
101                sig_a.parameters.len() == sig_b.parameters.len()
102            }
103
104            // Default case
105            _ => self.compatible_with_storage_and_view(other, type_cache),
106        }
107    }
108
109    #[must_use]
110    pub fn compatible_with_storage_and_view(
111        &self,
112        other_view: &Self,
113        type_cache: &mut TypeCache,
114    ) -> bool {
115        let left_kind = self.lowest_common_denominator_vec_like_view(type_cache);
116        let right_kind = other_view.lowest_common_denominator_vec_like_view(type_cache);
117        if left_kind.is_some() && right_kind.is_some() {
118            let left = left_kind.unwrap();
119            let right = right_kind.unwrap();
120            match (left, right) {
121                (TypeKind::SliceView(a), TypeKind::SliceView(b)) => {
122                    type_cache.compatible_with(&a, &b)
123                }
124                (TypeKind::DynamicLengthVecView(a), TypeKind::DynamicLengthVecView(b)) => {
125                    type_cache.compatible_with(&a, &b)
126                }
127                _ => false,
128            }
129        } else {
130            match (&*self.kind, &*other_view.kind) {
131                (
132                    TypeKind::MapStorage(key_a, value_a, _),
133                    TypeKind::DynamicLengthMapView(key_b, value_b),
134                )
135                | (
136                    TypeKind::DynamicLengthMapView(key_a, value_a),
137                    TypeKind::MapStorage(key_b, value_b, _),
138                ) => {
139                    type_cache.compatible_with(key_a, key_b)
140                        && type_cache.compatible_with(value_a, value_b)
141                }
142                _ => false,
143            }
144        }
145    }
146
147    // Helper method for lowest_common_denominator_view
148    #[must_use]
149    pub fn lowest_common_denominator_vec_like_view(
150        &self,
151        type_cache: &mut TypeCache,
152    ) -> Option<TypeKind> {
153        match &*self.kind {
154            TypeKind::FixedCapacityAndLengthArray(inner, _size)
155            | TypeKind::QueueStorage(inner, _size)
156            | TypeKind::StackStorage(inner, _size)
157            | TypeKind::SparseStorage(inner, _size)
158            | TypeKind::VecStorage(inner, _size) => Some(TypeKind::SliceView(inner.clone())),
159
160            TypeKind::SliceView(inner)
161            | TypeKind::QueueView(inner)
162            | TypeKind::StackView(inner)
163            | TypeKind::SparseView(inner)
164            | TypeKind::DynamicLengthVecView(inner) => Some(TypeKind::SliceView(inner.clone())),
165
166            TypeKind::StringStorage(byte_type, size) => {
167                Some(TypeKind::DynamicLengthVecView(byte_type.clone()))
168            }
169
170            TypeKind::String => Some(TypeKind::DynamicLengthVecView(type_cache.byte())),
171
172            _ => None,
173        }
174    }
175
176    #[must_use]
177    pub fn strict_compatible_with_capacity(&self, other: &Self) -> bool {
178        match (&*self.kind, &*other.kind) {
179            (TypeKind::VecStorage(_, cap_a), TypeKind::VecStorage(_, cap_b)) => cap_a == cap_b,
180            (TypeKind::SparseStorage(_, cap_a), TypeKind::SparseStorage(_, cap_b)) => {
181                cap_a == cap_b
182            }
183            (TypeKind::QueueStorage(_, cap_a), TypeKind::QueueStorage(_, cap_b)) => cap_a == cap_b,
184            (TypeKind::StackStorage(_, cap_a), TypeKind::StackStorage(_, cap_b)) => cap_a == cap_b,
185            (TypeKind::MapStorage(_, _, cap_a), TypeKind::MapStorage(_, _, cap_b)) => {
186                cap_a == cap_b
187            }
188            (
189                TypeKind::GridStorage(_, rows_a, cols_a),
190                TypeKind::GridStorage(_, rows_b, cols_b),
191            ) => rows_a == rows_b && cols_a == cols_b,
192            // For all other types, default to regular compatibility
193            _ => self.id == other.id,
194        }
195    }
196}