mago_codex/ttype/template/
mod.rs1use foldhash::HashMap;
2use foldhash::fast::RandomState;
3use indexmap::IndexMap;
4
5use mago_word::Word;
6
7use crate::misc::GenericParent;
8use crate::ttype::union::TUnion;
9
10pub mod bounds;
11pub mod definition_type_replacer;
12pub mod inferred_type_replacer;
13pub mod variance;
14
15#[derive(Clone, Debug, PartialEq, Eq, Hash)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21pub struct GenericTemplate {
22 pub defining_entity: GenericParent,
24 pub constraint: TUnion,
26 pub default: Option<TUnion>,
29}
30
31#[derive(Clone, Debug, Default)]
32pub struct TemplateResult {
33 pub template_types: IndexMap<Word, Vec<GenericTemplate>, RandomState>,
34 pub lower_bounds: HashMap<Word, HashMap<GenericParent, Vec<TemplateBound>>>,
35 pub projections: HashMap<Word, crate::ttype::template::variance::Variance>,
36}
37
38#[derive(Clone, Debug, PartialEq, Eq, Hash)]
39pub struct TemplateBound {
40 pub bound_type: TUnion,
41 pub appearance_depth: usize,
42 pub argument_offset: Option<usize>,
43}
44
45impl GenericTemplate {
46 #[must_use]
48 pub fn new(template_source: GenericParent, template_type: TUnion) -> Self {
49 Self { defining_entity: template_source, constraint: template_type, default: None }
50 }
51
52 #[must_use]
54 pub fn with_default(mut self, default: Option<TUnion>) -> Self {
55 self.default = default;
56 self
57 }
58}
59
60impl TemplateResult {
61 #[must_use]
62 pub fn new(
63 template_types: IndexMap<Word, Vec<GenericTemplate>, RandomState>,
64 lower_bounds: HashMap<Word, HashMap<GenericParent, TUnion>>,
65 ) -> TemplateResult {
66 let mut new_lower_bounds = HashMap::default();
67
68 for (k, v) in lower_bounds {
69 let mut th = HashMap::default();
70
71 for (vk, vv) in v {
72 th.insert(vk, vec![TemplateBound::new(vv, 0, None)]);
73 }
74
75 new_lower_bounds.insert(k, th);
76 }
77
78 TemplateResult { template_types, lower_bounds: new_lower_bounds, projections: HashMap::default() }
79 }
80
81 #[must_use]
82 pub fn has_template_types(&self) -> bool {
83 !self.template_types.is_empty()
84 }
85
86 pub fn add_lower_bounds(&mut self, lower_bounds: HashMap<Word, HashMap<GenericParent, TUnion>>) {
87 for (k, v) in lower_bounds {
88 let mut th = HashMap::default();
89
90 for (vk, vv) in v {
91 th.insert(vk, vec![TemplateBound::new(vv, 0, None)]);
92 }
93
94 self.lower_bounds.insert(k, th);
95 }
96 }
97
98 pub fn add_lower_bound(&mut self, parameter_name: Word, generic_parent: GenericParent, bound: TUnion) {
99 let entry = self.lower_bounds.entry(parameter_name).or_default();
100
101 entry.entry(generic_parent).or_default().push(TemplateBound::new(bound, 0, None));
102 }
103
104 pub fn add_template_type(&mut self, parameter_name: Word, generic_parent: GenericParent, constraint: TUnion) {
105 let entry = self.template_types.entry(parameter_name).or_default();
106 entry.push(GenericTemplate::new(generic_parent, constraint));
107 }
108
109 #[must_use]
110 pub fn has_lower_bound(&self, parameter_name: Word, generic_parent: &GenericParent) -> bool {
111 self.lower_bounds
112 .get(¶meter_name)
113 .and_then(|bounds| bounds.get(generic_parent))
114 .is_some_and(|bounds| !bounds.is_empty())
115 }
116
117 #[must_use]
118 pub fn get_lower_bounds_for_class_like(
119 &self,
120 parameter_name: Word,
121 classlike_name: Word,
122 ) -> Option<&Vec<TemplateBound>> {
123 self.lower_bounds.get(¶meter_name).and_then(|bounds| bounds.get(&GenericParent::ClassLike(classlike_name)))
124 }
125}
126
127impl TemplateBound {
128 #[must_use]
129 pub fn new(bound_type: TUnion, appearance_depth: usize, argument_offset: Option<usize>) -> Self {
130 Self { bound_type, appearance_depth, argument_offset }
131 }
132}