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}