Skip to main content

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}