mago_codex/ttype/
resolution.rs

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