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