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        // Since `Never` (!) types never return, then it is safe to be it compatible with anything
16        if matches!(&*other.kind, TypeKind::Never) {
17            return true;
18        }
19
20        // Since `Never` (!) types never return, then it is safe to be it compatible with anything
21        if matches!(&*self.kind, TypeKind::Never) {
22            return true;
23        }
24
25        match (&*self.kind, &*other.kind) {
26            // Direct comparisons for primitive types
27            (TypeKind::Int, TypeKind::Int) => true,
28            (TypeKind::Float, TypeKind::Float) => true,
29            (TypeKind::Bool, TypeKind::Bool) => true,
30            (TypeKind::Codepoint, TypeKind::Codepoint) => true,
31            (TypeKind::StringView(..), TypeKind::StringView(..)) => true,
32            (TypeKind::Unit, TypeKind::Unit) => true,
33
34            // For container types, we compare their structure but delegate inner compatibility
35            // checks to TypeCache.compatible_with
36            (TypeKind::Optional(a), TypeKind::Optional(b)) => type_cache.compatible_with(a, b),
37
38            (TypeKind::VecStorage(a, _), TypeKind::VecStorage(b, _)) => {
39                type_cache.compatible_with(a, b)
40            }
41            (TypeKind::SparseStorage(a, _), TypeKind::SparseStorage(b, _)) => {
42                type_cache.compatible_with(a, b)
43            }
44            (TypeKind::QueueStorage(a, _), TypeKind::QueueStorage(b, _)) => {
45                type_cache.compatible_with(a, b)
46            }
47
48            (TypeKind::StackStorage(a, _), TypeKind::StackStorage(b, _)) => {
49                type_cache.compatible_with(a, b)
50            }
51
52            (TypeKind::MapStorage(a_key, a_value, _), TypeKind::MapStorage(b_key, b_value, _)) => {
53                type_cache.compatible_with(a_key, b_key)
54                    && type_cache.compatible_with(a_value, b_value)
55            }
56
57            (
58                TypeKind::GridStorage(a, rows_a, cols_a),
59                TypeKind::GridStorage(b, rows_b, cols_b),
60            ) => rows_a >= rows_b && cols_a >= cols_b && type_cache.compatible_with(a, b),
61
62            (TypeKind::SliceView(a), TypeKind::SliceView(b)) => type_cache.compatible_with(a, b),
63            (TypeKind::SparseView(a), TypeKind::SparseView(b)) => type_cache.compatible_with(a, b),
64            (TypeKind::QueueView(a), TypeKind::QueueView(b)) => type_cache.compatible_with(a, b),
65            (TypeKind::StackView(a), TypeKind::StackView(b)) => type_cache.compatible_with(a, b),
66            (TypeKind::DynamicLengthVecView(a), TypeKind::DynamicLengthVecView(b)) => {
67                type_cache.compatible_with(a, b)
68            }
69            (
70                TypeKind::DynamicLengthMapView(a_key, a_value),
71                TypeKind::DynamicLengthMapView(b_key, b_value),
72            ) => {
73                type_cache.compatible_with(a_key, b_key)
74                    && type_cache.compatible_with(a_value, b_value)
75            }
76
77            (
78                TypeKind::FixedCapacityAndLengthArray(a, size_a),
79                TypeKind::FixedCapacityAndLengthArray(b, size_b),
80            ) => {
81                size_a == size_b && type_cache.compatible_with(a, b) // Fixed arrays must have the same size
82            }
83
84            (TypeKind::Tuple(elems_a), TypeKind::Tuple(elems_b)) => {
85                elems_a.len() == elems_b.len() // Tuples must have same length
86            }
87
88            (TypeKind::AnonymousStruct(anon_a), TypeKind::AnonymousStruct(anon_b)) => {
89                anon_a.field_name_sorted_fields.len() == anon_b.field_name_sorted_fields.len()
90                    && anon_a
91                        .field_name_sorted_fields
92                        .keys()
93                        .all(|key| anon_b.field_name_sorted_fields.contains_key(key))
94            }
95
96            (TypeKind::NamedStruct(named_a), TypeKind::NamedStruct(named_b)) => {
97                named_a.assigned_name == named_b.assigned_name
98                    && type_cache
99                        .compatible_with(&named_a.anon_struct_type, &named_b.anon_struct_type)
100            }
101
102            (TypeKind::Enum(enum_a), TypeKind::Enum(enum_b)) => {
103                enum_a.assigned_name == enum_b.assigned_name
104                    && enum_a.instantiated_type_parameters.len()
105                        == enum_b.instantiated_type_parameters.len()
106            }
107
108            (TypeKind::Function(sig_a), TypeKind::Function(sig_b)) => {
109                sig_a.parameters.len() == sig_b.parameters.len()
110            }
111
112            // Default case
113            _ => self.compatible_with_storage_and_view(other, type_cache),
114        }
115    }
116
117    #[must_use]
118    pub fn compatible_with_storage_and_view(
119        &self,
120        other_view: &Self,
121        type_cache: &mut TypeCache,
122    ) -> bool {
123        if matches!(&*self.kind, TypeKind::StringView(..))
124            && matches!(
125                &*other_view.kind,
126                TypeKind::VecStorage(inner_type, ..) | TypeKind::DynamicLengthVecView(inner_type)
127            )
128        {
129            match &*other_view.kind {
130                TypeKind::VecStorage(inner_type, ..)
131                | TypeKind::DynamicLengthVecView(inner_type) => {
132                    //let byte_type = type_cache.byte();
133                    return false;
134                }
135                _ => {}
136            }
137        }
138
139        if matches!(&*self.kind, TypeKind::StringStorage(..))
140            && matches!(&*other_view.kind, TypeKind::StringView(inner_type, ..))
141        {
142            //return false;
143        }
144
145        let left_kind = self.lowest_common_denominator_vec_like_view();
146        let right_kind = other_view.lowest_common_denominator_vec_like_view();
147        if left_kind.is_some() && right_kind.is_some() {
148            let left = left_kind.unwrap();
149            let right = right_kind.unwrap();
150            match (left, right) {
151                (TypeKind::SliceView(a), TypeKind::SliceView(b)) => {
152                    type_cache.compatible_with(&a, &b)
153                }
154                (TypeKind::DynamicLengthVecView(a), TypeKind::DynamicLengthVecView(b)) => {
155                    type_cache.compatible_with(&a, &b)
156                }
157                _ => false,
158            }
159        } else {
160            match (&*self.kind, &*other_view.kind) {
161                (
162                    TypeKind::MapStorage(key_a, value_a, _),
163                    TypeKind::DynamicLengthMapView(key_b, value_b),
164                )
165                | (
166                    TypeKind::DynamicLengthMapView(key_a, value_a),
167                    TypeKind::MapStorage(key_b, value_b, _),
168                ) => {
169                    type_cache.compatible_with(key_a, key_b)
170                        && type_cache.compatible_with(value_a, value_b)
171                }
172                _ => false,
173            }
174        }
175    }
176
177    // Helper method for lowest_common_denominator_view
178    #[must_use]
179    pub fn lowest_common_denominator_vec_like_view(&self) -> Option<TypeKind> {
180        match &*self.kind {
181            TypeKind::FixedCapacityAndLengthArray(inner, _)
182            | TypeKind::QueueStorage(inner, _)
183            | TypeKind::StackStorage(inner, _)
184            | TypeKind::SparseStorage(inner, _)
185            | TypeKind::StringStorage(inner, _, _)
186            | TypeKind::VecStorage(inner, _) => Some(TypeKind::SliceView(inner.clone())),
187
188            TypeKind::SliceView(inner)
189            | TypeKind::QueueView(inner)
190            | TypeKind::StackView(inner)
191            | TypeKind::SparseView(inner)
192            | TypeKind::StringView(inner, _)
193            | TypeKind::DynamicLengthVecView(inner) => Some(TypeKind::SliceView(inner.clone())),
194
195            _ => None,
196        }
197    }
198
199    #[must_use]
200    pub fn strict_compatible_with_capacity(&self, other: &Self) -> bool {
201        match (&*self.kind, &*other.kind) {
202            (TypeKind::VecStorage(_, cap_a), TypeKind::VecStorage(_, cap_b)) => cap_a == cap_b,
203            (TypeKind::SparseStorage(_, cap_a), TypeKind::SparseStorage(_, cap_b)) => {
204                cap_a == cap_b
205            }
206            (TypeKind::QueueStorage(_, cap_a), TypeKind::QueueStorage(_, cap_b)) => cap_a == cap_b,
207            (TypeKind::StackStorage(_, cap_a), TypeKind::StackStorage(_, cap_b)) => cap_a == cap_b,
208            (TypeKind::MapStorage(_, _, cap_a), TypeKind::MapStorage(_, _, cap_b)) => {
209                cap_a == cap_b
210            }
211            (
212                TypeKind::GridStorage(_, rows_a, cols_a),
213                TypeKind::GridStorage(_, rows_b, cols_b),
214            ) => rows_a == rows_b && cols_a == cols_b,
215            // For all other types, default to regular compatibility
216            _ => self.id == other.id,
217        }
218    }
219}