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;
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}