mago_codex/ttype/
resolution.rs

1use serde::Deserialize;
2use serde::Serialize;
3
4use crate::misc::GenericParent;
5use crate::ttype::union::TUnion;
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, Hash, Serialize, Deserialize)]
13pub struct TypeResolutionContext {
14    /// Definitions of template types available in this context, including their constraints.
15    template_definitions: Vec<(String, Vec<(GenericParent, TUnion)>)>,
16
17    /// Concrete types that template parameters (often from an outer scope) resolve to
18    /// within this specific context.
19    resolved_template_types: Vec<(String, TUnion)>,
20}
21
22/// Provides a default, empty type resolution context.
23impl Default for TypeResolutionContext {
24    fn default() -> Self {
25        Self::new()
26    }
27}
28
29impl TypeResolutionContext {
30    /// Creates a new, empty `TypeResolutionContext` with no defined or resolved template types.
31    pub fn new() -> Self {
32        Self { template_definitions: vec![], resolved_template_types: vec![] }
33    }
34
35    /// Checks if this context is empty, meaning it has no template definitions or resolved types.
36    #[inline]
37    pub fn is_empty(&self) -> bool {
38        self.template_definitions.is_empty() && self.resolved_template_types.is_empty()
39    }
40
41    /// Adds a template type definition (e.g., from an `@template T of Constraint` tag).
42    ///
43    /// # Arguments
44    ///
45    /// * `name`: The name of the template parameter (e.g., `"T"`).
46    /// * `constraints`: A list of constraints, each specifying the origin (parent) and the constraint type.
47    pub fn with_template_definition(mut self, name: String, constraints: Vec<(GenericParent, TUnion)>) -> Self {
48        self.template_definitions.push((name, constraints));
49        self
50    }
51
52    /// Adds a mapping indicating that a template parameter resolves to a specific concrete type
53    /// within this context.
54    ///
55    /// # Arguments
56    ///
57    /// * `name`: The name of the template parameter (e.g., `"T"`).
58    /// * `resolved_type`: The concrete `TUnion` type that `name` resolves to here.
59    pub fn with_resolved_template_type(mut self, name: String, resolved_type: TUnion) -> Self {
60        self.resolved_template_types.push((name, resolved_type));
61        self
62    }
63
64    /// Returns a slice of the defined template parameters and their constraints for this context.
65    #[inline]
66    pub fn get_template_definitions(&self) -> &[(String, Vec<(GenericParent, TUnion)>)] {
67        &self.template_definitions
68    }
69
70    /// Returns a mutable slice of the defined template parameters and their constraints for this context.
71    #[inline]
72    pub fn get_template_definitions_mut(&mut self) -> &mut [(String, Vec<(GenericParent, TUnion)>)] {
73        &mut self.template_definitions
74    }
75
76    /// Returns a slice of the template parameters that have resolved to concrete types in this context.
77    #[inline]
78    pub fn get_resolved_template_types(&self) -> &[(String, TUnion)] {
79        &self.resolved_template_types
80    }
81
82    /// Returns a mutable slice of the template parameters that have resolved to concrete types in this context.
83    #[inline]
84    pub fn get_resolved_template_types_mut(&mut self) -> &mut [(String, TUnion)] {
85        &mut self.resolved_template_types
86    }
87
88    /// Looks up the constraints for a specific template parameter defined in this context.
89    ///
90    /// # Arguments
91    ///
92    /// * `name`: The name of the template parameter (e.g., `"T"`) to look up.
93    ///
94    /// # Returns
95    ///
96    /// `Some` containing a reference to the vector of constraints if the template is defined, `None` otherwise.
97    pub fn get_template_definition(&self, name: &str) -> Option<&Vec<(GenericParent, TUnion)>> {
98        self.template_definitions.iter().find(|(n, _)| n == name).map(|(_, constraints)| constraints)
99    }
100
101    /// Checks if a specific template parameter is defined in this context.
102    ///
103    /// # Arguments
104    ///
105    /// * `name`: The name of the template parameter (e.g., `"T"`) to check.
106    ///
107    /// # Returns
108    ///
109    /// `true` if the template parameter is defined, `false` otherwise.
110    pub fn has_template_definition(&self, name: &str) -> bool {
111        self.template_definitions.iter().any(|(n, _)| n == name)
112    }
113
114    /// Looks up the concrete type that a specific template parameter resolves to in this context.
115    ///
116    /// # Arguments
117    ///
118    /// * `name`: The name of the template parameter (e.g., `"T"`) to look up.
119    ///
120    /// # Returns
121    ///
122    /// `Some` containing a reference to the resolved `TUnion` type if found, `None` otherwise.
123    /// Note: If multiple entries exist for the same name (due to shadowing or errors),
124    /// this currently returns the first match found.
125    pub fn get_resolved_template_type(&self, name: &str) -> Option<&TUnion> {
126        self.resolved_template_types
127            .iter()
128            // Iterate in reverse if shadowing means the *last* added binding is correct
129            // .rev()
130            .find(|(n, _)| n == name)
131            .map(|(_, resolved_type)| resolved_type)
132    }
133
134    /// Checks if this context contains any template definitions or resolved template types.
135    #[inline]
136    pub fn has_templates(&self) -> bool {
137        !self.template_definitions.is_empty() || !self.resolved_template_types.is_empty()
138    }
139
140    /// Checks if a specific template parameter has a concrete resolved type in this context.
141    #[inline]
142    pub fn is_template_resolved(&self, name: &str) -> bool {
143        self.resolved_template_types.iter().any(|(n, _)| n == name)
144    }
145
146    /// Merges another `TypeResolutionContext` into this one, combining their template definitions
147    /// and resolved types.
148    #[inline]
149    pub fn merge(&mut self, other: TypeResolutionContext) {
150        self.template_definitions.extend(other.template_definitions);
151        self.resolved_template_types.extend(other.resolved_template_types);
152    }
153}