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}