mago_codex/ttype/resolution.rs
1use mago_word::Word;
2use mago_word::WordMap;
3use mago_word::WordSet;
4
5use crate::ttype::template::GenericTemplate;
6
7/// Holds contextual information necessary for resolving generic template types (`@template`).
8///
9/// This context typically includes the definitions of template parameters available in the current scope
10/// (e.g., from class or function `@template` tags) and any concrete types that these templates
11/// have been resolved to (e.g., when a generic class is instantiated or a generic method is called).
12#[derive(Clone, Debug, PartialEq, Eq)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct TypeResolutionContext {
15 /// Definitions of template types available in this context, including their constraints.
16 template_definitions: WordMap<Vec<GenericTemplate>>,
17
18 /// Type aliases defined in the current class scope (from @type tags).
19 type_aliases: WordSet,
20
21 /// Imported type aliases (from @import-type tags).
22 /// Maps local alias name to (source class FQCN, original type name).
23 imported_type_aliases: WordMap<(Word, Word)>,
24}
25
26/// Provides a default, empty type resolution context.
27impl Default for TypeResolutionContext {
28 fn default() -> Self {
29 Self::new()
30 }
31}
32
33impl TypeResolutionContext {
34 /// Creates a new, empty `TypeResolutionContext` with no defined or resolved template types.
35 #[must_use]
36 pub fn new() -> Self {
37 Self {
38 template_definitions: WordMap::default(),
39 type_aliases: WordSet::default(),
40 imported_type_aliases: WordMap::default(),
41 }
42 }
43
44 /// Checks if this context is empty, meaning it has no template definitions or resolved types.
45 #[inline]
46 #[must_use]
47 pub fn is_empty(&self) -> bool {
48 self.template_definitions.is_empty() && self.type_aliases.is_empty() && self.imported_type_aliases.is_empty()
49 }
50
51 /// Adds a template type definition (e.g., from an `@template T of Constraint` tag).
52 ///
53 /// # Arguments
54 ///
55 /// * `name`: The name of the template parameter (e.g., `"T"`).
56 /// * `constraints`: A list of constraints for the template parameter.
57 #[must_use]
58 pub fn with_template_definition(mut self, name: Word, constraints: Vec<GenericTemplate>) -> Self {
59 self.template_definitions.insert(name, constraints);
60 self
61 }
62
63 /// Returns a mutable reference to the template definitions map.
64 #[inline]
65 pub fn get_template_definitions_mut(&mut self) -> &mut WordMap<Vec<GenericTemplate>> {
66 &mut self.template_definitions
67 }
68
69 /// Looks up the constraints for a specific template parameter defined in this context.
70 ///
71 /// # Arguments
72 ///
73 /// * `name`: The name of the template parameter (e.g., `"T"`) to look up.
74 ///
75 /// # Returns
76 ///
77 /// `Some` containing a reference to the vector of constraints if the template is defined, `None` otherwise.
78 #[must_use]
79 pub fn get_template_definition(&self, name: Word) -> Option<&Vec<GenericTemplate>> {
80 self.template_definitions.get(&name)
81 }
82
83 /// Checks if a specific template parameter is defined in this context.
84 ///
85 /// # Arguments
86 ///
87 /// * `name`: The name of the template parameter (e.g., `"T"`) to check.
88 ///
89 /// # Returns
90 ///
91 /// `true` if the template parameter is defined, `false` otherwise.
92 #[must_use]
93 pub fn has_template_definition(&self, name: Word) -> bool {
94 self.template_definitions.contains_key(&name)
95 }
96
97 /// Adds type aliases from a class to this context.
98 ///
99 /// # Arguments
100 ///
101 /// * `aliases`: A set of type alias names.
102 #[must_use]
103 pub fn with_type_aliases(mut self, aliases: WordSet) -> Self {
104 self.type_aliases = aliases;
105 self
106 }
107
108 /// Adds a single type alias to this context.
109 ///
110 /// # Arguments
111 ///
112 /// * `name`: The name of the type alias to add.
113 #[must_use]
114 pub fn with_type_alias(mut self, name: Word) -> Self {
115 self.type_aliases.insert(name);
116 self
117 }
118
119 /// Checks if a specific type alias is defined in this context.
120 ///
121 /// # Arguments
122 ///
123 /// * `name`: The name of the type alias to check.
124 #[must_use]
125 pub fn has_type_alias(&self, name: Word) -> bool {
126 self.type_aliases.contains(&name)
127 }
128
129 /// Adds an imported type alias to this context.
130 ///
131 /// # Arguments
132 ///
133 /// * `local_name`: The local name of the imported alias (possibly renamed with "as").
134 /// * `source_class`: The FQCN of the class where the type alias is defined.
135 /// * `original_name`: The original name of the type alias in the source class.
136 #[must_use]
137 pub fn with_imported_type_alias(mut self, local_name: Word, source_class: Word, original_name: Word) -> Self {
138 self.imported_type_aliases.insert(local_name, (source_class, original_name));
139 self
140 }
141
142 /// Looks up an imported type alias in this context.
143 ///
144 /// # Arguments
145 ///
146 /// * `name`: The local name of the imported alias to look up.
147 ///
148 /// # Returns
149 ///
150 /// `Some` containing a reference to (`source_class`, `original_name`) if found, `None` otherwise.
151 #[must_use]
152 pub fn get_imported_type_alias(&self, name: Word) -> Option<&(Word, Word)> {
153 self.imported_type_aliases.get(&name)
154 }
155}