Skip to main content

lisette_semantics/checker/registration/
builtins.rs

1use syntax::EcoString;
2use syntax::types::Type;
3
4use crate::checker::Checker;
5
6impl Checker<'_, '_> {
7    fn builtin_qualified_name(&mut self, type_name: &str) -> EcoString {
8        self.lookup_qualified_name(type_name)
9            .map(EcoString::from)
10            .unwrap_or_else(|| panic!("Builtin type {type_name} not found in store"))
11    }
12
13    fn builtin_type(&mut self, type_name: &str) -> Type {
14        if let Some(ty) = self.builtins.get(type_name) {
15            return ty.clone();
16        }
17
18        let qualified_name = self.builtin_qualified_name(type_name);
19
20        let ty = self
21            .store
22            .get_type(&qualified_name)
23            .unwrap_or_else(|| panic!("Builtin type {type_name} not found in store"));
24
25        let body = match &ty {
26            Type::Forall { body, .. } => body.as_ref().clone(),
27            _ => ty.clone(),
28        };
29
30        self.builtins.insert(type_name.to_string(), body.clone());
31
32        body
33    }
34
35    pub fn type_unit(&self) -> Type {
36        Type::unit()
37    }
38
39    pub fn type_never(&self) -> Type {
40        Type::Never
41    }
42
43    pub fn type_int(&mut self) -> Type {
44        self.builtin_type("int")
45    }
46
47    pub fn type_float(&mut self) -> Type {
48        self.builtin_type("float64")
49    }
50
51    pub fn type_string(&mut self) -> Type {
52        self.builtin_type("string")
53    }
54
55    pub fn type_char(&mut self) -> Type {
56        self.builtin_type("rune")
57    }
58
59    pub fn type_bool(&mut self) -> Type {
60        self.builtin_type("bool")
61    }
62
63    pub fn type_complex128(&mut self) -> Type {
64        self.builtin_type("complex128")
65    }
66
67    pub fn type_unknown(&mut self) -> Type {
68        self.builtin_type("Unknown")
69    }
70
71    pub fn type_slice(&mut self, element_type: Type) -> Type {
72        Type::Constructor {
73            id: self.builtin_qualified_name("Slice"),
74            params: vec![element_type],
75            underlying_ty: None,
76        }
77    }
78
79    pub fn type_reference(&mut self, inner_type: Type) -> Type {
80        Type::Constructor {
81            id: self.builtin_qualified_name("Ref"),
82            params: vec![inner_type],
83            underlying_ty: None,
84        }
85    }
86
87    pub fn type_map(&mut self, key_type: Type, value_type: Type) -> Type {
88        Type::Constructor {
89            id: self.builtin_qualified_name("Map"),
90            params: vec![key_type, value_type],
91            underlying_ty: None,
92        }
93    }
94
95    pub fn type_result(&mut self, ok_type: Type, error_type: Type) -> Type {
96        Type::Constructor {
97            id: self.builtin_qualified_name("Result"),
98            params: vec![ok_type, error_type],
99            underlying_ty: None,
100        }
101    }
102
103    pub fn type_option(&mut self, some_type: Type) -> Type {
104        Type::Constructor {
105            id: self.builtin_qualified_name("Option"),
106            params: vec![some_type],
107            underlying_ty: None,
108        }
109    }
110
111    pub fn type_panic_value(&mut self) -> Type {
112        Type::Constructor {
113            id: self.builtin_qualified_name("PanicValue"),
114            params: vec![],
115            underlying_ty: None,
116        }
117    }
118
119    pub fn type_range(&mut self, element_type: Type) -> Type {
120        Type::Constructor {
121            id: self.builtin_qualified_name("Range"),
122            params: vec![element_type],
123            underlying_ty: None,
124        }
125    }
126
127    pub fn type_range_inclusive(&mut self, element_type: Type) -> Type {
128        Type::Constructor {
129            id: self.builtin_qualified_name("RangeInclusive"),
130            params: vec![element_type],
131            underlying_ty: None,
132        }
133    }
134
135    pub fn type_range_from(&mut self, element_type: Type) -> Type {
136        Type::Constructor {
137            id: self.builtin_qualified_name("RangeFrom"),
138            params: vec![element_type],
139            underlying_ty: None,
140        }
141    }
142
143    pub fn type_range_to(&mut self, element_type: Type) -> Type {
144        Type::Constructor {
145            id: self.builtin_qualified_name("RangeTo"),
146            params: vec![element_type],
147            underlying_ty: None,
148        }
149    }
150
151    pub fn type_range_to_inclusive(&mut self, element_type: Type) -> Type {
152        Type::Constructor {
153            id: self.builtin_qualified_name("RangeToInclusive"),
154            params: vec![element_type],
155            underlying_ty: None,
156        }
157    }
158
159    /// Checks if a type is a generic container (Option, Result) with interface type parameters.
160    /// Used to determine when to use the expected type for codegen instead of the inferred type.
161    pub fn is_generic_container_with_interface(&self, ty: &Type) -> bool {
162        let Type::Constructor { id, params, .. } = ty.resolve() else {
163            return false;
164        };
165
166        if id != "prelude.Option" && id != "prelude.Result" {
167            return false;
168        }
169
170        params.iter().any(|p| {
171            if let Type::Constructor { id, .. } = p.resolve() {
172                self.store.get_interface(&id).is_some()
173            } else {
174                false
175            }
176        })
177    }
178
179    pub fn has_interface_type_param(&self, ty: &Type) -> bool {
180        let Type::Constructor { params, .. } = ty.resolve() else {
181            return false;
182        };
183
184        params.iter().any(|p| {
185            if let Type::Constructor { id, .. } = p.resolve() {
186                self.store.get_interface(&id).is_some()
187            } else {
188                false
189            }
190        })
191    }
192}