Skip to main content

mago_codex/ttype/
resolution.rs

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