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