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