1use cairo_lang_defs::ids::EnumId;
2use cairo_lang_defs::{
3 db::DefsGroup,
4 ids::{
5 ExternFunctionId, FreeFunctionId, ImplDefId, ImplItemId, LookupItemId, ModuleId,
6 ModuleItemId, SubmoduleId, TopLevelLanguageElementId, TraitFunctionId, TraitItemId,
7 },
8};
9use cairo_lang_filesystem::ids::CrateId;
10use cairo_lang_semantic::items::imp::ImplSemantic;
11use cairo_lang_semantic::items::trt::TraitSemantic;
12use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
13use salsa::{Database, Update};
14
15pub const BOOL_PARTIAL_EQ_PATH: &str = "core::BoolPartialEq";
16pub const PANIC_PATH: &str = "core::panics::panic";
17pub const PANIC_WITH_BYTE_ARRAY_PATH: &str = "core::panics::panic_with_byte_array";
18pub const T_COPY_CLONE_PATH: &str = "core::clone::TCopyClone";
19pub const PARTIAL_ORD_LE_PATH: &str = "core::traits::PartialOrd::le";
20pub const PARTIAL_ORD_GE_PATH: &str = "core::traits::PartialOrd::ge";
21pub const ADD_TRAIT_FUNCTION_PATH: &str = "core::traits::Add::add";
22pub const SUB_TRAIT_FUNCTION_PATH: &str = "core::traits::Sub::sub";
23pub const INTEGER_MODULE_PATH: &str = "core::integer";
24pub const INTO_TRAIT_FUNCTION_PATH: &str = "core::traits::Into::into";
25pub const TRY_INTO_TRAIT_FUNCTION_PATH: &str = "core::traits::TryInto::try_into";
26pub const OPTION_TYPE_PATH: &str = "core::option::Option";
27
28static CORELIB_ITEM_PATHS: [&str; 12] = [
29 BOOL_PARTIAL_EQ_PATH,
30 PANIC_PATH,
31 PANIC_WITH_BYTE_ARRAY_PATH,
32 T_COPY_CLONE_PATH,
33 PARTIAL_ORD_LE_PATH,
34 PARTIAL_ORD_GE_PATH,
35 ADD_TRAIT_FUNCTION_PATH,
36 SUB_TRAIT_FUNCTION_PATH,
37 INTEGER_MODULE_PATH,
38 OPTION_TYPE_PATH,
39 INTO_TRAIT_FUNCTION_PATH,
40 TRY_INTO_TRAIT_FUNCTION_PATH,
41];
42
43#[derive(PartialEq, Eq, Hash, Debug, Clone, Update)]
44pub struct CorelibContext<'db> {
45 corelib_items: OrderedHashMap<String, Option<LookupItemId<'db>>>,
46}
47
48impl<'db> CorelibContext<'db> {
49 pub(crate) fn new(db: &'db dyn Database) -> Self {
50 let core_crate_id = CrateId::core(db);
51 let modules = db.crate_modules(core_crate_id);
52 Self {
53 corelib_items: CORELIB_ITEM_PATHS
54 .iter()
55 .map(|path| {
56 for module in modules.iter() {
57 let item_id = find_item_with_path(db, *module, path);
58 if item_id.is_some() {
59 return (path.to_string(), item_id);
60 }
61 }
62
63 (path.to_string(), None)
64 })
65 .collect(),
66 }
67 }
68
69 pub fn get_bool_partial_eq_impl_id(&self) -> ImplDefId<'db> {
71 let item = self
72 .corelib_items
73 .get(BOOL_PARTIAL_EQ_PATH)
74 .expect("Expected BoolPartialEq to be present in corelib items")
75 .expect("Expected BoolPartialEq to be defined in the corelib");
76 match item {
77 LookupItemId::ModuleItem(ModuleItemId::Impl(id)) => id,
78 _ => unreachable!("Expected BoolPartialEq to be an ImplDefId"),
79 }
80 }
81
82 pub fn get_panic_function_id(&self) -> ExternFunctionId<'db> {
83 let item = self
84 .corelib_items
85 .get(PANIC_PATH)
86 .expect("Expected panic to be present in corelib items")
87 .expect("Expected panic to be defined in the corelib");
88 match item {
89 LookupItemId::ModuleItem(ModuleItemId::ExternFunction(id)) => id,
90 _ => unreachable!("Expected panic to be a ExternFunction"),
91 }
92 }
93
94 pub fn get_panic_with_byte_array_function_id(&self) -> FreeFunctionId<'db> {
95 let item = self
96 .corelib_items
97 .get(PANIC_WITH_BYTE_ARRAY_PATH)
98 .expect("Expected panic_with_byte_array to be present in corelib items")
99 .expect("Expected panic_with_byte_array to be defined in the corelib");
100 match item {
101 LookupItemId::ModuleItem(ModuleItemId::FreeFunction(id)) => id,
102 _ => unreachable!("Expected panic_with_byte_array to be a FreeFunction"),
103 }
104 }
105
106 pub fn get_t_copy_clone_impl_id(&self) -> ImplDefId<'db> {
107 let item = self
108 .corelib_items
109 .get(T_COPY_CLONE_PATH)
110 .expect("Expected TCopyClone to be present in corelib items")
111 .expect("Expected TCopyClone to be defined in the corelib");
112 match item {
113 LookupItemId::ModuleItem(ModuleItemId::Impl(id)) => id,
114 _ => unreachable!("Expected TCopyClone to be an ImplDefId"),
115 }
116 }
117
118 pub fn get_partial_ord_le_trait_function_id(&self) -> TraitFunctionId<'db> {
119 let item = self
120 .corelib_items
121 .get(PARTIAL_ORD_LE_PATH)
122 .expect("Expected PartialOrd::le to be present in corelib items")
123 .expect("Expected PartialOrd::le to be defined in the corelib");
124 match item {
125 LookupItemId::TraitItem(TraitItemId::Function(id)) => id,
126 _ => unreachable!("Expected PartialOrd::le to be a TraitFunctionId"),
127 }
128 }
129
130 pub fn get_partial_ord_ge_trait_function_id(&self) -> TraitFunctionId<'db> {
131 let item = self
132 .corelib_items
133 .get(PARTIAL_ORD_GE_PATH)
134 .expect("Expected PartialOrd::ge to be present in corelib items")
135 .expect("Expected PartialOrd::ge to be defined in the corelib");
136 match item {
137 LookupItemId::TraitItem(TraitItemId::Function(id)) => id,
138 _ => unreachable!("Expected PartialOrd::ge to be a TraitFunctionId"),
139 }
140 }
141
142 pub fn get_add_trait_function_id(&self) -> TraitFunctionId<'db> {
143 let item = self
144 .corelib_items
145 .get(ADD_TRAIT_FUNCTION_PATH)
146 .expect("Expected Add::add to be present in corelib items")
147 .expect("Expected Add::add to be defined in the corelib");
148 match item {
149 LookupItemId::TraitItem(TraitItemId::Function(id)) => id,
150 _ => unreachable!("Expected Add::add to be a TraitFunctionId"),
151 }
152 }
153
154 pub fn get_sub_trait_function_id(&self) -> TraitFunctionId<'db> {
155 let item = self
156 .corelib_items
157 .get(SUB_TRAIT_FUNCTION_PATH)
158 .expect("Expected Sub::sub to be present in corelib items")
159 .expect("Expected Sub::sub to be defined in the corelib");
160 match item {
161 LookupItemId::TraitItem(TraitItemId::Function(id)) => id,
162 _ => unreachable!("Expected Sub::sub to be a TraitFunctionId"),
163 }
164 }
165
166 pub fn get_integer_module_id(&self) -> SubmoduleId<'db> {
167 let item = self
168 .corelib_items
169 .get(INTEGER_MODULE_PATH)
170 .expect("Expected integer module to be present in corelib items")
171 .expect("Expected integer module to be defined in the corelib");
172 match item {
173 LookupItemId::ModuleItem(ModuleItemId::Submodule(id)) => id,
174 _ => unreachable!("Expected integer module to be a Submodule"),
175 }
176 }
177
178 pub fn get_into_trait_function_id(&self) -> TraitFunctionId<'db> {
179 let item = self
180 .corelib_items
181 .get(INTO_TRAIT_FUNCTION_PATH)
182 .expect("Expected Into::into to be present in corelib items")
183 .expect("Expected Into::into to be defined in the corelib");
184 match item {
185 LookupItemId::TraitItem(TraitItemId::Function(id)) => id,
186 _ => unreachable!("Expected Into::into to be a TraitFunctionId"),
187 }
188 }
189
190 pub fn get_try_into_trait_function_id(&self) -> TraitFunctionId<'db> {
191 let item = self
192 .corelib_items
193 .get(TRY_INTO_TRAIT_FUNCTION_PATH)
194 .expect("Expected TryInto::try_into to be present in corelib items")
195 .expect("Expected TryInto::try_into to be defined in the corelib");
196 match item {
197 LookupItemId::TraitItem(TraitItemId::Function(id)) => id,
198 _ => unreachable!("Expected TryInto::try_into to be a TraitFunctionId"),
199 }
200 }
201 pub fn get_option_enum_id(&self) -> EnumId<'db> {
202 let item = self
203 .corelib_items
204 .get(OPTION_TYPE_PATH)
205 .expect("Expected Option to be present in corelib items")
206 .expect("Expected Option to be defined in the corelib");
207 match item {
208 LookupItemId::ModuleItem(ModuleItemId::Enum(id)) => id,
209 _ => unreachable!("Expected Option to be a EnumId"),
210 }
211 }
212}
213
214fn find_item_with_path<'db>(
215 db: &'db dyn Database,
216 module_id: ModuleId<'db>,
217 path: &str,
218) -> Option<LookupItemId<'db>> {
219 let items = module_id.module_data(db).ok()?.items(db);
220 for item in items.iter() {
221 if item.full_path(db) == path {
222 return Some(LookupItemId::ModuleItem(*item));
223 }
224 match item {
225 ModuleItemId::Submodule(submodule_id) => {
226 let submodule_item =
227 find_item_with_path(db, ModuleId::Submodule(*submodule_id), path);
228 if submodule_item.is_some() {
229 return submodule_item;
230 }
231 }
232 ModuleItemId::Impl(impl_id) => {
233 if let Ok(functions) = db.impl_functions(*impl_id) {
234 for (_, impl_fn_id) in functions.iter() {
235 if impl_fn_id.full_path(db) == path {
236 return Some(LookupItemId::ImplItem(ImplItemId::Function(*impl_fn_id)));
237 }
238 }
239 }
240
241 if let Ok(types) = db.impl_types(*impl_id) {
242 for (impl_type_id, _) in types.iter() {
243 if impl_type_id.full_path(db) == path {
244 return Some(LookupItemId::ImplItem(ImplItemId::Type(*impl_type_id)));
245 }
246 }
247 }
248
249 if let Ok(consts) = db.impl_constants(*impl_id) {
250 for (impl_const_id, _) in consts.iter() {
251 if impl_const_id.full_path(db) == path {
252 return Some(LookupItemId::ImplItem(ImplItemId::Constant(
253 *impl_const_id,
254 )));
255 }
256 }
257 }
258 }
259 ModuleItemId::Trait(trait_id) => {
260 if let Ok(functions) = db.trait_functions(*trait_id) {
261 for (_, trait_fn_id) in functions.iter() {
262 if trait_fn_id.full_path(db) == path {
263 return Some(LookupItemId::TraitItem(TraitItemId::Function(
264 *trait_fn_id,
265 )));
266 }
267 }
268 }
269
270 if let Ok(types) = db.trait_types(*trait_id) {
271 for (_, trait_type_id) in types.iter() {
272 if trait_type_id.full_path(db) == path {
273 return Some(LookupItemId::TraitItem(TraitItemId::Type(
274 *trait_type_id,
275 )));
276 }
277 }
278 }
279
280 if let Ok(consts) = db.trait_constants(*trait_id) {
281 for (_, trait_const_id) in consts.iter() {
282 if trait_const_id.full_path(db) == path {
283 return Some(LookupItemId::TraitItem(TraitItemId::Constant(
284 *trait_const_id,
285 )));
286 }
287 }
288 }
289 }
290 _ => (),
292 }
293 }
294 None
295}