mago_codex/ttype/resolution.rs
1use mago_word::Word;
2use mago_word::WordMap;
3use mago_word::WordSet;
4
5use crate::ttype::template::GenericTemplate;
6use crate::ttype::union::TUnion;
7
8/// Holds contextual information necessary for resolving generic template types (`@template`).
9///
10/// This context typically includes the definitions of template parameters available in the current scope
11/// (e.g., from class or function `@template` tags) and any concrete types that these templates
12/// have been resolved to (e.g., when a generic class is instantiated or a generic method is called).
13#[derive(Clone, Debug, PartialEq, Eq)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub struct TypeResolutionContext {
16 /// Definitions of template types available in this context, including their constraints.
17 template_definitions: WordMap<Vec<GenericTemplate>>,
18
19 /// Concrete types that template parameters (often from an outer scope) resolve to
20 /// within this specific context.
21 resolved_template_types: WordMap<TUnion>,
22
23 /// Type aliases defined in the current class scope (from @type tags).
24 type_aliases: WordSet,
25
26 /// Imported type aliases (from @import-type tags).
27 /// Maps local alias name to (source class FQCN, original type name).
28 imported_type_aliases: WordMap<(Word, Word)>,
29}
30
31/// Provides a default, empty type resolution context.
32impl Default for TypeResolutionContext {
33 fn default() -> Self {
34 Self::new()
35 }
36}
37
38impl TypeResolutionContext {
39 /// Creates a new, empty `TypeResolutionContext` with no defined or resolved template types.
40 #[must_use]
41 pub fn new() -> Self {
42 Self {
43 template_definitions: WordMap::default(),
44 resolved_template_types: WordMap::default(),
45 type_aliases: WordSet::default(),
46 imported_type_aliases: WordMap::default(),
47 }
48 }
49
50 /// Checks if this context is empty, meaning it has no template definitions or resolved types.
51 #[inline]
52 #[must_use]
53 pub fn is_empty(&self) -> bool {
54 self.template_definitions.is_empty()
55 && self.resolved_template_types.is_empty()
56 && self.type_aliases.is_empty()
57 && self.imported_type_aliases.is_empty()
58 }
59
60 /// Adds a template type definition (e.g., from an `@template T of Constraint` tag).
61 ///
62 /// # Arguments
63 ///
64 /// * `name`: The name of the template parameter (e.g., `"T"`).
65 /// * `constraints`: A list of constraints for the template parameter.
66 #[must_use]
67 pub fn with_template_definition(mut self, name: Word, constraints: Vec<GenericTemplate>) -> Self {
68 self.template_definitions.insert(name, constraints);
69 self
70 }
71
72 /// Adds a mapping indicating that a template parameter resolves to a specific concrete type
73 /// within this context.
74 ///
75 /// # Arguments
76 ///
77 /// * `name`: The name of the template parameter (e.g., `"T"`).
78 /// * `resolved_type`: The concrete `TUnion` type that `name` resolves to here.
79 #[must_use]
80 pub fn with_resolved_template_type(mut self, name: Word, resolved_type: TUnion) -> Self {
81 self.resolved_template_types.insert(name, resolved_type);
82 self
83 }
84
85 /// Returns a reference to the template definitions map.
86 #[inline]
87 #[must_use]
88 pub fn get_template_definitions(&self) -> &WordMap<Vec<GenericTemplate>> {
89 &self.template_definitions
90 }
91
92 /// Returns a mutable reference to the template definitions map.
93 #[inline]
94 pub fn get_template_definitions_mut(&mut self) -> &mut WordMap<Vec<GenericTemplate>> {
95 &mut self.template_definitions
96 }
97
98 /// Returns a reference to the resolved template types map.
99 #[inline]
100 #[must_use]
101 pub fn get_resolved_template_types(&self) -> &WordMap<TUnion> {
102 &self.resolved_template_types
103 }
104
105 /// Returns a mutable reference to the resolved template types map.
106 #[inline]
107 pub fn get_resolved_template_types_mut(&mut self) -> &mut WordMap<TUnion> {
108 &mut self.resolved_template_types
109 }
110
111 /// Looks up the constraints for a specific template parameter defined in this context.
112 ///
113 /// # Arguments
114 ///
115 /// * `name`: The name of the template parameter (e.g., `"T"`) to look up.
116 ///
117 /// # Returns
118 ///
119 /// `Some` containing a reference to the vector of constraints if the template is defined, `None` otherwise.
120 #[must_use]
121 pub fn get_template_definition(&self, name: Word) -> Option<&Vec<GenericTemplate>> {
122 self.template_definitions.get(&name)
123 }
124
125 /// Checks if a specific template parameter is defined in this context.
126 ///
127 /// # Arguments
128 ///
129 /// * `name`: The name of the template parameter (e.g., `"T"`) to check.
130 ///
131 /// # Returns
132 ///
133 /// `true` if the template parameter is defined, `false` otherwise.
134 #[must_use]
135 pub fn has_template_definition(&self, name: Word) -> bool {
136 self.template_definitions.contains_key(&name)
137 }
138
139 /// Adds type aliases from a class to this context.
140 ///
141 /// # Arguments
142 ///
143 /// * `aliases`: A set of type alias names.
144 #[must_use]
145 pub fn with_type_aliases(mut self, aliases: WordSet) -> Self {
146 self.type_aliases = aliases;
147 self
148 }
149
150 /// Adds a single type alias to this context.
151 ///
152 /// # Arguments
153 ///
154 /// * `name`: The name of the type alias to add.
155 #[must_use]
156 pub fn with_type_alias(mut self, name: Word) -> Self {
157 self.type_aliases.insert(name);
158 self
159 }
160
161 /// Checks if a specific type alias is defined in this context.
162 ///
163 /// # Arguments
164 ///
165 /// * `name`: The name of the type alias to check.
166 #[must_use]
167 pub fn has_type_alias(&self, name: Word) -> bool {
168 self.type_aliases.contains(&name)
169 }
170
171 /// Adds an imported type alias to this context.
172 ///
173 /// # Arguments
174 ///
175 /// * `local_name`: The local name of the imported alias (possibly renamed with "as").
176 /// * `source_class`: The FQCN of the class where the type alias is defined.
177 /// * `original_name`: The original name of the type alias in the source class.
178 #[must_use]
179 pub fn with_imported_type_alias(mut self, local_name: Word, source_class: Word, original_name: Word) -> Self {
180 self.imported_type_aliases.insert(local_name, (source_class, original_name));
181 self
182 }
183
184 /// Looks up an imported type alias in this context.
185 ///
186 /// # Arguments
187 ///
188 /// * `name`: The local name of the imported alias to look up.
189 ///
190 /// # Returns
191 ///
192 /// `Some` containing a reference to (`source_class`, `original_name`) if found, `None` otherwise.
193 #[must_use]
194 pub fn get_imported_type_alias(&self, name: Word) -> Option<&(Word, Word)> {
195 self.imported_type_aliases.get(&name)
196 }
197
198 /// Checks if a specific imported type alias is defined in this context.
199 ///
200 /// # Arguments
201 ///
202 /// * `name`: The local name of the imported alias to check.
203 #[must_use]
204 pub fn has_imported_type_alias(&self, name: Word) -> bool {
205 self.imported_type_aliases.contains_key(&name)
206 }
207
208 /// Looks up the concrete type that a specific template parameter resolves to in this context.
209 ///
210 /// # Arguments
211 ///
212 /// * `name`: The name of the template parameter (e.g., `"T"`) to look up.
213 ///
214 /// # Returns
215 ///
216 /// `Some` containing a reference to the resolved `TUnion` type if found, `None` otherwise.
217 #[must_use]
218 pub fn get_resolved_template_type(&self, name: Word) -> Option<&TUnion> {
219 self.resolved_template_types.get(&name)
220 }
221
222 /// Checks if this context contains any template definitions or resolved template types.
223 #[inline]
224 #[must_use]
225 pub fn has_templates(&self) -> bool {
226 !self.template_definitions.is_empty() || !self.resolved_template_types.is_empty()
227 }
228
229 /// Checks if a specific template parameter has a concrete resolved type in this context.
230 #[inline]
231 #[must_use]
232 pub fn is_template_resolved(&self, name: Word) -> bool {
233 self.resolved_template_types.contains_key(&name)
234 }
235
236 /// Merges another `TypeResolutionContext` into this one, combining their template definitions
237 /// and resolved types.
238 #[inline]
239 pub fn merge(&mut self, other: TypeResolutionContext) {
240 self.template_definitions.extend(other.template_definitions);
241 self.resolved_template_types.extend(other.resolved_template_types);
242 }
243}