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 pub fn new(
26 template_types: IndexMap<Atom, Vec<(GenericParent, TUnion)>, RandomState>,
27 lower_bounds: IndexMap<Atom, HashMap<GenericParent, TUnion>, RandomState>,
28 ) -> TemplateResult {
29 let mut new_lower_bounds = IndexMap::with_hasher(RandomState::new());
30
31 for (k, v) in lower_bounds {
32 let mut th = HashMap::default();
33
34 for (vk, vv) in v {
35 th.insert(vk, vec![TemplateBound::new(vv, 0, None, None)]);
36 }
37
38 new_lower_bounds.insert(k, th);
39 }
40
41 TemplateResult {
42 template_types,
43 lower_bounds: new_lower_bounds,
44 upper_bounds: IndexMap::with_hasher(RandomState::new()),
45 readonly: false,
46 upper_bounds_unintersectable_types: Vec::new(),
47 }
48 }
49
50 pub fn has_template_types(&self) -> bool {
51 !self.template_types.is_empty()
52 }
53
54 pub fn add_lower_bounds(&mut self, lower_bounds: IndexMap<Atom, HashMap<GenericParent, TUnion>, RandomState>) {
55 for (k, v) in lower_bounds {
56 let mut th = HashMap::default();
57
58 for (vk, vv) in v {
59 th.insert(vk, vec![TemplateBound::new(vv, 0, None, None)]);
60 }
61
62 self.lower_bounds.insert(k, th);
63 }
64 }
65
66 pub fn add_lower_bound(&mut self, parameter_name: Atom, generic_parent: GenericParent, bound: TUnion) {
67 let entry = self.lower_bounds.entry(parameter_name).or_default();
68
69 entry.entry(generic_parent).or_default().push(TemplateBound::new(bound, 0, None, None));
70 }
71
72 pub fn add_template_type(&mut self, parameter_name: Atom, generic_parent: GenericParent, constraint: TUnion) {
73 let entry = self.template_types.entry(parameter_name).or_default();
74 entry.push((generic_parent, constraint));
75 }
76
77 pub fn add_upper_bound(&mut self, parameter_name: Atom, generic_parent: GenericParent, bound: TemplateBound) {
78 let entry = self.upper_bounds.entry(parameter_name).or_default();
79 entry.insert(generic_parent, bound);
80 }
81
82 pub fn add_upper_bound_unintersectable_type(&mut self, bound: TUnion) {
83 self.upper_bounds_unintersectable_types.push(bound);
84 }
85
86 pub fn has_lower_bound(&self, parameter_name: &Atom, generic_parent: &GenericParent) -> bool {
87 self.lower_bounds
88 .get(parameter_name)
89 .and_then(|bounds| bounds.get(generic_parent))
90 .is_some_and(|bounds| !bounds.is_empty())
91 }
92
93 pub fn has_lower_bound_for_class_like(&self, parameter_name: &Atom, classlike_name: &Atom) -> bool {
94 self.has_lower_bound(parameter_name, &GenericParent::ClassLike(*classlike_name))
95 }
96
97 pub fn get_lower_bounds_for_class_like(
98 &self,
99 parameter_name: &Atom,
100 classlike_name: &Atom,
101 ) -> Option<&Vec<TemplateBound>> {
102 self.lower_bounds.get(parameter_name).and_then(|bounds| bounds.get(&GenericParent::ClassLike(*classlike_name)))
103 }
104}
105
106#[derive(Clone, Debug, PartialEq, Eq, Hash)]
107pub struct TemplateBound {
108 pub bound_type: TUnion,
109 pub appearance_depth: usize,
110 pub argument_offset: Option<usize>,
111 pub equality_bound_classlike: Option<Atom>,
112 pub span: Option<Span>,
113}
114
115impl TemplateBound {
116 pub fn new(
117 bound_type: TUnion,
118 appearance_depth: usize,
119 argument_offset: Option<usize>,
120 equality_bound_classlike: Option<Atom>,
121 ) -> Self {
122 Self { bound_type, appearance_depth, argument_offset, equality_bound_classlike, span: None }
123 }
124
125 pub fn of_type(bound_type: TUnion) -> Self {
126 Self { bound_type, appearance_depth: 0, argument_offset: None, equality_bound_classlike: None, span: None }
127 }
128}