1use std::sync::Arc;
2
3use cairo_lang_defs::ids::{
4 EnumId, GenericTypeId, ImplDefId, ModuleId, ModuleItemId, NamedLanguageElementId,
5 TraitFunctionId, TraitId,
6};
7use cairo_lang_diagnostics::{Maybe, ToOption};
8use cairo_lang_filesystem::ids::CrateId;
9use cairo_lang_syntax::node::Terminal;
10use cairo_lang_syntax::node::ast::{self, BinaryOperator, UnaryOperator};
11use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
12use cairo_lang_utils::{
13 Intern, LookupIntern, OptionFrom, extract_matches, require, try_extract_matches,
14};
15use num_bigint::BigInt;
16use num_traits::{Num, Signed, ToPrimitive, Zero};
17use smol_str::SmolStr;
18
19use crate::db::SemanticGroup;
20use crate::diagnostic::SemanticDiagnosticKind;
21use crate::expr::compute::ComputationContext;
22use crate::expr::inference::Inference;
23use crate::helper::ModuleHelper;
24use crate::items::constant::ConstValue;
25use crate::items::enm::SemanticEnumEx;
26use crate::items::functions::{GenericFunctionId, ImplGenericFunctionId};
27use crate::items::imp::ImplLongId;
28use crate::items::trt::{
29 ConcreteTraitGenericFunctionId, ConcreteTraitGenericFunctionLongId, ConcreteTraitId,
30};
31use crate::items::us::SemanticUseEx;
32use crate::resolve::ResolvedGenericItem;
33use crate::types::{ConcreteEnumLongId, ConcreteExternTypeLongId};
34use crate::{
35 ConcreteEnumId, ConcreteFunction, ConcreteImplLongId, ConcreteTypeId, ConcreteVariant, Expr,
36 ExprId, ExprTuple, FunctionId, FunctionLongId, GenericArgumentId, TypeId, TypeLongId, semantic,
37};
38
39pub fn core_module(db: &dyn SemanticGroup) -> ModuleId {
41 let core_crate = db.core_crate();
42 ModuleId::CrateRoot(core_crate)
43}
44
45pub fn get_submodule(
47 db: &dyn SemanticGroup,
48 base_module: ModuleId,
49 submodule_name: &str,
50) -> Option<ModuleId> {
51 let submodules = db.module_submodules(base_module).ok()?;
52 let syntax_db = db.upcast();
53 for (submodule_id, submodule) in submodules.iter() {
54 if submodule.name(syntax_db).text(syntax_db) == submodule_name {
55 return Some(ModuleId::Submodule(*submodule_id));
56 }
57 }
58 None
59}
60
61pub fn core_submodule(db: &dyn SemanticGroup, submodule_name: &str) -> ModuleId {
64 get_submodule(db, core_module(db), submodule_name)
65 .unwrap_or_else(|| panic!("`{submodule_name}` is not a core submodule."))
66}
67
68pub fn core_crate(db: &dyn SemanticGroup) -> CrateId {
70 CrateId::core(db)
71}
72
73pub fn bounded_int_ty(db: &dyn SemanticGroup, min: BigInt, max: BigInt) -> TypeId {
75 let internal = core_submodule(db, "internal");
76 let bounded_int = get_submodule(db, internal, "bounded_int")
77 .expect("Could not find bounded_int submodule in corelib.");
78 let felt252_ty = db.core_info().felt252;
79 let lower_id = ConstValue::Int(min, felt252_ty).intern(db);
80 let upper_id = ConstValue::Int(max, felt252_ty).intern(db);
81 try_get_ty_by_name(
82 db,
83 bounded_int,
84 "BoundedInt".into(),
85 vec![GenericArgumentId::Constant(lower_id), GenericArgumentId::Constant(upper_id)],
86 )
87 .expect("could not find")
88}
89
90pub fn core_nonzero_ty(db: &dyn SemanticGroup, inner_type: TypeId) -> TypeId {
91 get_ty_by_name(
92 db,
93 core_submodule(db, "zeroable"),
94 "NonZero".into(),
95 vec![GenericArgumentId::Type(inner_type)],
96 )
97}
98
99pub fn core_result_ty(db: &dyn SemanticGroup, ok_type: TypeId, err_type: TypeId) -> TypeId {
100 get_ty_by_name(
101 db,
102 core_submodule(db, "result"),
103 "Result".into(),
104 vec![GenericArgumentId::Type(ok_type), GenericArgumentId::Type(err_type)],
105 )
106}
107
108pub fn core_option_ty(db: &dyn SemanticGroup, some_type: TypeId) -> TypeId {
109 get_ty_by_name(
110 db,
111 core_submodule(db, "option"),
112 "Option".into(),
113 vec![GenericArgumentId::Type(some_type)],
114 )
115}
116
117pub fn core_box_ty(db: &dyn SemanticGroup, inner_type: TypeId) -> TypeId {
118 get_ty_by_name(
119 db,
120 core_submodule(db, "box"),
121 "Box".into(),
122 vec![GenericArgumentId::Type(inner_type)],
123 )
124}
125
126pub fn core_array_felt252_ty(db: &dyn SemanticGroup) -> TypeId {
127 get_core_ty_by_name(db, "Array".into(), vec![GenericArgumentId::Type(db.core_info().felt252)])
128}
129
130pub fn try_get_core_ty_by_name(
131 db: &dyn SemanticGroup,
132 name: SmolStr,
133 generic_args: Vec<GenericArgumentId>,
134) -> Result<TypeId, SemanticDiagnosticKind> {
135 try_get_ty_by_name(db, db.core_module(), name, generic_args)
136}
137
138pub fn try_get_ty_by_name(
139 db: &dyn SemanticGroup,
140 module: ModuleId,
141 name: SmolStr,
142 generic_args: Vec<GenericArgumentId>,
143) -> Result<TypeId, SemanticDiagnosticKind> {
144 let module_item_id = db
146 .module_item_by_name(module, name.clone())
147 .map_err(|_| SemanticDiagnosticKind::UnknownType)?
148 .ok_or(SemanticDiagnosticKind::UnknownType)?;
149 let generic_type = match module_item_id {
150 ModuleItemId::Use(use_id) => {
151 db.use_resolved_item(use_id).to_option().and_then(|resolved_generic_item| {
152 try_extract_matches!(resolved_generic_item, ResolvedGenericItem::GenericType)
153 })
154 }
155 ModuleItemId::TypeAlias(module_type_alias_id) => {
156 let ty = db
157 .module_type_alias_resolved_type(module_type_alias_id)
158 .expect("Could not find type alias.");
159 assert!(
160 db.module_type_alias_generic_params(module_type_alias_id).unwrap().is_empty(),
161 "Cannot get type aliases with params from corelib."
162 );
163 return Ok(ty);
164 }
165 _ => GenericTypeId::option_from(module_item_id),
166 }
167 .unwrap_or_else(|| panic!("{name} is not a type."));
168
169 Ok(semantic::TypeLongId::Concrete(semantic::ConcreteTypeId::new(
170 db,
171 generic_type,
172 generic_args,
173 ))
174 .intern(db))
175}
176
177pub fn get_core_ty_by_name(
178 db: &dyn SemanticGroup,
179 name: SmolStr,
180 generic_args: Vec<GenericArgumentId>,
181) -> TypeId {
182 try_get_core_ty_by_name(db, name, generic_args).unwrap()
183}
184
185pub fn get_ty_by_name(
186 db: &dyn SemanticGroup,
187 module: ModuleId,
188 name: SmolStr,
189 generic_args: Vec<GenericArgumentId>,
190) -> TypeId {
191 try_get_ty_by_name(db, module, name, generic_args).unwrap()
192}
193
194pub fn core_bool_ty(db: &dyn SemanticGroup) -> TypeId {
195 let core_module = db.core_module();
196 let generic_type = db
198 .module_item_by_name(core_module, "bool".into())
199 .expect("Failed to load core lib.")
200 .and_then(GenericTypeId::option_from)
201 .expect("Type bool was not found in core lib.");
202 semantic::TypeLongId::Concrete(semantic::ConcreteTypeId::new(db, generic_type, vec![]))
203 .intern(db)
204}
205
206pub fn core_bool_enum(db: &dyn SemanticGroup) -> ConcreteEnumId {
209 let core_module = db.core_module();
210 let enum_id = db
212 .module_item_by_name(core_module, "bool".into())
213 .expect("Failed to load core lib.")
214 .and_then(EnumId::option_from)
215 .expect("Type bool was not found in core lib.");
216 ConcreteEnumLongId { enum_id, generic_args: vec![] }.intern(db)
217}
218
219pub fn false_variant(db: &dyn SemanticGroup) -> ConcreteVariant {
221 get_core_enum_concrete_variant(db, "bool", vec![], "False")
222}
223
224pub fn true_variant(db: &dyn SemanticGroup) -> ConcreteVariant {
226 get_core_enum_concrete_variant(db, "bool", vec![], "True")
227}
228
229pub fn jump_nz_zero_variant(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteVariant {
231 get_enum_concrete_variant(
232 db,
233 core_submodule(db, "zeroable"),
234 "IsZeroResult",
235 vec![GenericArgumentId::Type(ty)],
236 "Zero",
237 )
238}
239
240pub fn jump_nz_nonzero_variant(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteVariant {
242 get_enum_concrete_variant(
243 db,
244 core_submodule(db, "zeroable"),
245 "IsZeroResult",
246 vec![GenericArgumentId::Type(ty)],
247 "NonZero",
248 )
249}
250
251pub fn option_some_variant(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteVariant {
253 get_enum_concrete_variant(
254 db,
255 core_submodule(db, "option"),
256 "Option",
257 vec![GenericArgumentId::Type(ty)],
258 "Some",
259 )
260}
261
262pub fn option_none_variant(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteVariant {
264 get_enum_concrete_variant(
265 db,
266 core_submodule(db, "option"),
267 "Option",
268 vec![GenericArgumentId::Type(ty)],
269 "None",
270 )
271}
272
273pub fn result_ok_variant(db: &dyn SemanticGroup, ok_ty: TypeId, err_ty: TypeId) -> ConcreteVariant {
275 get_enum_concrete_variant(
276 db,
277 core_submodule(db, "result"),
278 "Result",
279 vec![GenericArgumentId::Type(ok_ty), GenericArgumentId::Type(err_ty)],
280 "Ok",
281 )
282}
283
284pub fn result_err_variant(
286 db: &dyn SemanticGroup,
287 ok_ty: TypeId,
288 err_ty: TypeId,
289) -> ConcreteVariant {
290 get_enum_concrete_variant(
291 db,
292 core_submodule(db, "result"),
293 "Result",
294 vec![GenericArgumentId::Type(ok_ty), GenericArgumentId::Type(err_ty)],
295 "Err",
296 )
297}
298
299pub fn signed_int_result_in_range_variant(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteVariant {
301 get_enum_concrete_variant(
302 db,
303 core_submodule(db, "integer"),
304 "SignedIntegerResult",
305 vec![GenericArgumentId::Type(ty)],
306 "InRange",
307 )
308}
309pub fn signed_int_result_underflow_variant(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteVariant {
311 get_enum_concrete_variant(
312 db,
313 core_submodule(db, "integer"),
314 "SignedIntegerResult",
315 vec![GenericArgumentId::Type(ty)],
316 "Underflow",
317 )
318}
319pub fn signed_int_result_overflow_variant(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteVariant {
321 get_enum_concrete_variant(
322 db,
323 core_submodule(db, "integer"),
324 "SignedIntegerResult",
325 vec![GenericArgumentId::Type(ty)],
326 "Overflow",
327 )
328}
329
330pub fn false_literal_expr(
333 ctx: &mut ComputationContext<'_>,
334 stable_ptr: ast::ExprPtr,
335) -> semantic::Expr {
336 get_bool_variant_expr(ctx, "bool", "False", stable_ptr)
337}
338
339pub fn true_literal_expr(
342 ctx: &mut ComputationContext<'_>,
343 stable_ptr: ast::ExprPtr,
344) -> semantic::Expr {
345 get_bool_variant_expr(ctx, "bool", "True", stable_ptr)
346}
347
348fn get_bool_variant_expr(
351 ctx: &mut ComputationContext<'_>,
352 enum_name: &str,
353 variant_name: &str,
354 stable_ptr: ast::ExprPtr,
355) -> semantic::Expr {
356 let concrete_variant = get_core_enum_concrete_variant(ctx.db, enum_name, vec![], variant_name);
357 semantic::Expr::EnumVariantCtor(semantic::ExprEnumVariantCtor {
358 variant: concrete_variant,
359 value_expr: unit_expr(ctx, stable_ptr),
360 ty: core_bool_ty(ctx.db),
361 stable_ptr,
362 })
363}
364
365pub fn get_enum_concrete_variant(
368 db: &dyn SemanticGroup,
369 module_id: ModuleId,
370 enum_name: &str,
371 generic_args: Vec<GenericArgumentId>,
372 variant_name: &str,
373) -> ConcreteVariant {
374 let ty = get_ty_by_name(db, module_id, enum_name.into(), generic_args);
375 let concrete_ty = extract_matches!(ty.lookup_intern(db), TypeLongId::Concrete);
376 let concrete_enum_id = extract_matches!(concrete_ty, ConcreteTypeId::Enum);
377 let enum_id = concrete_enum_id.enum_id(db);
378 let variant_id = db.enum_variants(enum_id).unwrap()[variant_name];
379 let variant = db.variant_semantic(enum_id, variant_id).unwrap();
380 db.concrete_enum_variant(concrete_enum_id, &variant).unwrap()
381}
382
383pub fn get_core_enum_concrete_variant(
386 db: &dyn SemanticGroup,
387 enum_name: &str,
388 generic_args: Vec<GenericArgumentId>,
389 variant_name: &str,
390) -> ConcreteVariant {
391 get_enum_concrete_variant(db, core_module(db), enum_name, generic_args, variant_name)
392}
393
394pub fn unit_ty(db: &dyn SemanticGroup) -> TypeId {
396 semantic::TypeLongId::Tuple(vec![]).intern(db)
397}
398
399pub fn never_ty(db: &dyn SemanticGroup) -> TypeId {
401 let core_module = db.core_module();
402 let generic_type = db
404 .module_item_by_name(core_module, "never".into())
405 .expect("Failed to load core lib.")
406 .and_then(GenericTypeId::option_from)
407 .expect("Type bool was not found in core lib.");
408 semantic::TypeLongId::Concrete(semantic::ConcreteTypeId::new(db, generic_type, vec![]))
409 .intern(db)
410}
411
412pub enum ErrorPropagationType {
413 Option { some_variant: ConcreteVariant, none_variant: ConcreteVariant },
414 Result { ok_variant: ConcreteVariant, err_variant: ConcreteVariant },
415}
416impl ErrorPropagationType {
417 pub fn ok_variant(&self) -> &ConcreteVariant {
418 match self {
419 ErrorPropagationType::Option { some_variant, .. } => some_variant,
420 ErrorPropagationType::Result { ok_variant, .. } => ok_variant,
421 }
422 }
423 pub fn err_variant(&self) -> &ConcreteVariant {
424 match self {
425 ErrorPropagationType::Option { none_variant, .. } => none_variant,
426 ErrorPropagationType::Result { err_variant, .. } => err_variant,
427 }
428 }
429}
430
431pub fn unwrap_error_propagation_type(
434 db: &dyn SemanticGroup,
435 ty: TypeId,
436) -> Option<ErrorPropagationType> {
437 match ty.lookup_intern(db) {
438 TypeLongId::Concrete(semantic::ConcreteTypeId::Enum(enm)) => {
440 if let [ok_variant, err_variant] =
441 db.concrete_enum_variants(enm).to_option()?.as_slice()
442 {
443 let name = enm.enum_id(db.upcast()).name(db.upcast());
444 if name == "Option" {
445 return Some(ErrorPropagationType::Option {
446 some_variant: ok_variant.clone(),
447 none_variant: err_variant.clone(),
448 });
449 } else if name == "Result" {
450 return Some(ErrorPropagationType::Result {
451 ok_variant: ok_variant.clone(),
452 err_variant: err_variant.clone(),
453 });
454 }
455 }
456 None
457 }
458 TypeLongId::GenericParameter(_) => todo!(
459 "When generic types are supported, if type is of matching type, allow unwrapping it \
460 to type."
461 ),
462 TypeLongId::Concrete(
463 semantic::ConcreteTypeId::Struct(_) | semantic::ConcreteTypeId::Extern(_),
464 )
465 | TypeLongId::Tuple(_)
466 | TypeLongId::Snapshot(_)
467 | TypeLongId::Var(_)
468 | TypeLongId::Coupon(_)
469 | TypeLongId::ImplType(_)
470 | TypeLongId::Missing(_)
471 | TypeLongId::FixedSizeArray { .. }
472 | TypeLongId::Closure(_) => None,
473 }
474}
475
476pub fn unit_expr(ctx: &mut ComputationContext<'_>, stable_ptr: ast::ExprPtr) -> ExprId {
479 ctx.arenas.exprs.alloc(Expr::Tuple(ExprTuple {
480 items: Vec::new(),
481 ty: TypeLongId::Tuple(Vec::new()).intern(ctx.db),
482 stable_ptr,
483 }))
484}
485
486pub fn core_unary_operator(
487 db: &dyn SemanticGroup,
488 inference: &mut Inference<'_>,
489 unary_op: &UnaryOperator,
490 stable_ptr: SyntaxStablePtrId,
491) -> Maybe<Result<ConcreteTraitGenericFunctionId, SemanticDiagnosticKind>> {
492 let info = db.core_info();
493 let (trait_id, trait_fn) = match unary_op {
494 UnaryOperator::Minus(_) => (info.neg_trt, info.neg_fn),
495 UnaryOperator::Not(_) => (info.not_trt, info.not_fn),
496 UnaryOperator::BitNot(_) => (info.bitnot_trt, info.bitnot_fn),
497 UnaryOperator::At(_) => unreachable!("@ is not an unary operator."),
498 UnaryOperator::Desnap(_) => unreachable!("* is not an unary operator."),
499 };
500 Ok(Ok(get_core_trait_function_infer(db, inference, trait_id, trait_fn, stable_ptr)))
501}
502
503pub fn core_binary_operator(
504 db: &dyn SemanticGroup,
505 inference: &mut Inference<'_>,
506 binary_op: &BinaryOperator,
507 stable_ptr: SyntaxStablePtrId,
508) -> Maybe<Result<(ConcreteTraitGenericFunctionId, bool), SemanticDiagnosticKind>> {
509 let info = db.core_info();
510 let (trait_id, trait_fn, snapshot) = match binary_op {
511 BinaryOperator::Plus(_) => (info.add_trt, info.add_fn, false),
512 BinaryOperator::PlusEq(_) => (info.add_assign_trt, info.add_assign_fn, false),
513 BinaryOperator::Minus(_) => (info.sub_trt, info.sub_fn, false),
514 BinaryOperator::MinusEq(_) => (info.sub_assign_trt, info.sub_assign_fn, false),
515 BinaryOperator::Mul(_) => (info.mul_trt, info.mul_fn, false),
516 BinaryOperator::MulEq(_) => (info.mul_assign_trt, info.mul_assign_fn, false),
517 BinaryOperator::Div(_) => (info.div_trt, info.div_fn, false),
518 BinaryOperator::DivEq(_) => (info.div_assign_trt, info.div_assign_fn, false),
519 BinaryOperator::Mod(_) => (info.rem_trt, info.rem_fn, false),
520 BinaryOperator::ModEq(_) => (info.rem_assign_trt, info.rem_assign_fn, false),
521 BinaryOperator::EqEq(_) => (info.partialeq_trt, info.eq_fn, true),
522 BinaryOperator::Neq(_) => (info.partialeq_trt, info.ne_fn, true),
523 BinaryOperator::LE(_) => (info.partialord_trt, info.le_fn, false),
524 BinaryOperator::GE(_) => (info.partialord_trt, info.ge_fn, false),
525 BinaryOperator::LT(_) => (info.partialord_trt, info.lt_fn, false),
526 BinaryOperator::GT(_) => (info.partialord_trt, info.gt_fn, false),
527 BinaryOperator::And(_) => (info.bitand_trt, info.bitand_fn, false),
528 BinaryOperator::Or(_) => (info.bitor_trt, info.bitor_fn, false),
529 BinaryOperator::Xor(_) => (info.bitxor_trt, info.bitxor_fn, false),
530 BinaryOperator::DotDot(_) => (info.range_op_trt, info.range_fn, false),
531 BinaryOperator::DotDotEq(_) => {
532 (info.range_inclusive_op_trt, info.range_inclusive_fn, false)
533 }
534 _ => return Ok(Err(SemanticDiagnosticKind::UnknownBinaryOperator)),
535 };
536 Ok(Ok((get_core_trait_function_infer(db, inference, trait_id, trait_fn, stable_ptr), snapshot)))
537}
538
539pub fn felt252_sub(db: &dyn SemanticGroup) -> FunctionId {
540 get_core_function_impl_method(db, "Felt252Sub".into(), "sub".into())
541}
542
543fn get_core_function_impl_method(
545 db: &dyn SemanticGroup,
546 impl_name: SmolStr,
547 method_name: SmolStr,
548) -> FunctionId {
549 let core_module = db.core_module();
550 let module_item_id = db
551 .module_item_by_name(core_module, impl_name.clone())
552 .expect("Failed to load core lib.")
553 .unwrap_or_else(|| panic!("Impl '{impl_name}' was not found in core lib."));
554 let impl_def_id = match module_item_id {
555 ModuleItemId::Use(use_id) => {
556 db.use_resolved_item(use_id).to_option().and_then(|resolved_generic_item| {
557 try_extract_matches!(resolved_generic_item, ResolvedGenericItem::Impl)
558 })
559 }
560 _ => ImplDefId::option_from(module_item_id),
561 }
562 .unwrap_or_else(|| panic!("{impl_name} is not an impl."));
563 let impl_id =
564 ImplLongId::Concrete(ConcreteImplLongId { impl_def_id, generic_args: vec![] }.intern(db))
565 .intern(db);
566 let concrete_trait_id = db.impl_concrete_trait(impl_id).unwrap();
567 let function = db
568 .trait_functions(concrete_trait_id.trait_id(db))
569 .ok()
570 .and_then(|functions| functions.get(&method_name).cloned())
571 .unwrap_or_else(|| {
572 panic!("no {method_name} in {}.", concrete_trait_id.trait_id(db).name(db.upcast()))
573 });
574 FunctionLongId {
575 function: ConcreteFunction {
576 generic_function: GenericFunctionId::Impl(ImplGenericFunctionId { impl_id, function }),
577 generic_args: vec![],
578 },
579 }
580 .intern(db)
581}
582
583pub fn core_felt252_is_zero(db: &dyn SemanticGroup) -> FunctionId {
584 get_core_function_id(db, "felt252_is_zero".into(), vec![])
585}
586
587pub fn core_withdraw_gas_fns(db: &dyn SemanticGroup) -> [FunctionId; 2] {
589 let gas = core_submodule(db, "gas");
590 [
591 get_function_id(db, gas, "withdraw_gas".into(), vec![]),
592 get_function_id(db, gas, "withdraw_gas_all".into(), vec![]),
593 ]
594}
595
596pub fn internal_require_implicit(db: &dyn SemanticGroup) -> GenericFunctionId {
597 get_generic_function_id(db, core_submodule(db, "internal"), "require_implicit".into())
598}
599pub fn core_downcast(db: &dyn SemanticGroup, input: TypeId, output: TypeId) -> FunctionId {
601 let internal = core_submodule(db, "integer");
602
603 get_function_id(
604 db,
605 internal,
606 "downcast".into(),
607 vec![GenericArgumentId::Type(input), GenericArgumentId::Type(output)],
608 )
609}
610pub fn get_core_function_id(
612 db: &dyn SemanticGroup,
613 name: SmolStr,
614 generic_args: Vec<GenericArgumentId>,
615) -> FunctionId {
616 get_function_id(db, db.core_module(), name, generic_args)
617}
618
619pub fn get_function_id(
621 db: &dyn SemanticGroup,
622 module: ModuleId,
623 name: SmolStr,
624 generic_args: Vec<GenericArgumentId>,
625) -> FunctionId {
626 let generic_function = get_generic_function_id(db, module, name);
627
628 FunctionLongId { function: ConcreteFunction { generic_function, generic_args } }.intern(db)
629}
630
631pub fn get_core_generic_function_id(db: &dyn SemanticGroup, name: SmolStr) -> GenericFunctionId {
633 get_generic_function_id(db, db.core_module(), name)
634}
635
636pub fn get_generic_function_id(
638 db: &dyn SemanticGroup,
639 module: ModuleId,
640 name: SmolStr,
641) -> GenericFunctionId {
642 let module_item_id = db
643 .module_item_by_name(module, name.clone())
644 .expect("Failed to load core lib.")
645 .unwrap_or_else(|| panic!("Function '{name}' was not found in core lib."));
646 match module_item_id {
647 ModuleItemId::Use(use_id) => {
648 db.use_resolved_item(use_id).to_option().and_then(|resolved_generic_item| {
649 try_extract_matches!(resolved_generic_item, ResolvedGenericItem::GenericFunction)
650 })
651 }
652 _ => GenericFunctionId::option_from(module_item_id),
653 }
654 .unwrap_or_else(|| panic!("{name} is not a function."))
655}
656
657pub fn concrete_copy_trait(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteTraitId {
658 concrete_trait(db, db.core_info().copy_trt, vec![GenericArgumentId::Type(ty)])
659}
660
661pub fn concrete_drop_trait(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteTraitId {
662 concrete_trait(db, db.core_info().drop_trt, vec![GenericArgumentId::Type(ty)])
663}
664
665pub fn concrete_destruct_trait(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteTraitId {
666 concrete_trait(db, db.core_info().destruct_trt, vec![GenericArgumentId::Type(ty)])
667}
668
669pub fn concrete_panic_destruct_trait(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteTraitId {
670 concrete_trait(db, db.core_info().panic_destruct_trt, vec![GenericArgumentId::Type(ty)])
671}
672
673pub fn concrete_iterator_trait(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteTraitId {
674 concrete_trait(db, db.core_info().iterator_trt, vec![GenericArgumentId::Type(ty)])
675}
676
677pub fn fn_traits(db: &dyn SemanticGroup) -> [TraitId; 2] {
678 let info = db.core_info();
679 [info.fn_trt, info.fn_once_trt]
680}
681
682fn concrete_trait(
684 db: &dyn SemanticGroup,
685 trait_id: TraitId,
686 generic_args: Vec<GenericArgumentId>,
687) -> ConcreteTraitId {
688 semantic::ConcreteTraitLongId { trait_id, generic_args }.intern(db)
689}
690
691fn get_core_trait_function_infer(
694 db: &dyn SemanticGroup,
695 inference: &mut Inference<'_>,
696 trait_id: TraitId,
697 trait_function: TraitFunctionId,
698 stable_ptr: SyntaxStablePtrId,
699) -> ConcreteTraitGenericFunctionId {
700 let generic_params = db.trait_generic_params(trait_id).unwrap();
701 let generic_args = generic_params
702 .iter()
703 .map(|_| GenericArgumentId::Type(inference.new_type_var(Some(stable_ptr))))
704 .collect();
705 let concrete_trait_id = semantic::ConcreteTraitLongId { trait_id, generic_args }.intern(db);
706 ConcreteTraitGenericFunctionLongId::new(db, concrete_trait_id, trait_function).intern(db)
707}
708
709pub fn get_panic_ty(db: &dyn SemanticGroup, inner_ty: TypeId) -> TypeId {
710 get_core_ty_by_name(db.upcast(), "PanicResult".into(), vec![GenericArgumentId::Type(inner_ty)])
711}
712
713pub fn get_usize_ty(db: &dyn SemanticGroup) -> TypeId {
714 get_core_ty_by_name(db, "usize".into(), vec![])
715}
716
717pub fn get_convert_to_felt252_libfunc_name_by_type(
719 db: &dyn SemanticGroup,
720 ty: TypeId,
721) -> Option<FunctionId> {
722 let info = db.core_info();
723 if ty == info.u8 {
724 Some(get_function_id(db, core_submodule(db, "integer"), "u8_to_felt252".into(), vec![]))
725 } else if ty == info.u16 {
726 Some(get_function_id(db, core_submodule(db, "integer"), "u16_to_felt252".into(), vec![]))
727 } else if ty == info.u32 {
728 Some(get_function_id(db, core_submodule(db, "integer"), "u32_to_felt252".into(), vec![]))
729 } else if ty == info.u64 {
730 Some(get_function_id(db, core_submodule(db, "integer"), "u64_to_felt252".into(), vec![]))
731 } else if ty == info.u128 {
732 Some(get_function_id(db, core_submodule(db, "integer"), "u128_to_felt252".into(), vec![]))
733 } else if ty == info.i8 {
734 Some(get_function_id(db, core_submodule(db, "integer"), "i8_to_felt252".into(), vec![]))
735 } else if ty == info.i16 {
736 Some(get_function_id(db, core_submodule(db, "integer"), "i16_to_felt252".into(), vec![]))
737 } else if ty == info.i32 {
738 Some(get_function_id(db, core_submodule(db, "integer"), "i32_to_felt252".into(), vec![]))
739 } else if ty == info.i64 {
740 Some(get_function_id(db, core_submodule(db, "integer"), "i64_to_felt252".into(), vec![]))
741 } else if ty == info.i128 {
742 Some(get_function_id(db, core_submodule(db, "integer"), "i128_to_felt252".into(), vec![]))
743 } else {
744 None
745 }
746}
747
748#[derive(Clone, Debug, Eq, Hash, PartialEq)]
749pub enum LiteralError {
750 InvalidTypeForLiteral(TypeId),
751 OutOfRange(TypeId),
752}
753impl LiteralError {
754 pub fn format(&self, db: &dyn SemanticGroup) -> String {
755 match self {
756 Self::OutOfRange(ty) => format!(
757 "The value does not fit within the range of type {}.",
758 ty.format(db.upcast())
759 ),
760 Self::InvalidTypeForLiteral(ty) => {
761 format!("A numeric literal of type {} cannot be created.", ty.format(db.upcast()))
762 }
763 }
764 }
765}
766
767pub fn validate_literal(
770 db: &dyn SemanticGroup,
771 ty: TypeId,
772 value: &BigInt,
773) -> Result<(), LiteralError> {
774 let info = db.core_info();
775 let validate_out_of_range = |is_out_of_range: bool| {
776 if is_out_of_range { Err(LiteralError::OutOfRange(ty)) } else { Ok(()) }
777 };
778 if ty == info.felt252 {
779 validate_out_of_range(
780 value.abs()
781 > BigInt::from_str_radix(
782 "800000000000011000000000000000000000000000000000000000000000000",
783 16,
784 )
785 .unwrap(),
786 )
787 } else if ty == info.u8 {
788 validate_out_of_range(value.to_u8().is_none())
789 } else if ty == info.u16 {
790 validate_out_of_range(value.to_u16().is_none())
791 } else if ty == info.u32 {
792 validate_out_of_range(value.to_u32().is_none())
793 } else if ty == info.u64 {
794 validate_out_of_range(value.to_u64().is_none())
795 } else if ty == info.u128 {
796 validate_out_of_range(value.to_u128().is_none())
797 } else if ty == info.i8 {
798 validate_out_of_range(value.to_i8().is_none())
799 } else if ty == info.i16 {
800 validate_out_of_range(value.to_i16().is_none())
801 } else if ty == info.i32 {
802 validate_out_of_range(value.to_i32().is_none())
803 } else if ty == info.i64 {
804 validate_out_of_range(value.to_i64().is_none())
805 } else if ty == info.i128 {
806 validate_out_of_range(value.to_i128().is_none())
807 } else if ty == info.u256 {
808 validate_out_of_range(value.is_negative() || value.bits() > 256)
809 } else if ty == info.class_hash || ty == info.contract_address {
810 validate_out_of_range(value.is_negative() || value.bits() > 251)
811 } else if let Some(nz_wrapped_ty) = try_extract_nz_wrapped_type(db, ty) {
812 if value.is_zero() {
813 Err(LiteralError::OutOfRange(ty))
814 } else {
815 validate_literal(db, nz_wrapped_ty, value)
816 }
817 } else if let Some((min, max)) = try_extract_bounded_int_type_ranges(db, ty) {
818 validate_out_of_range(*value < min || *value > max)
819 } else {
820 Err(LiteralError::InvalidTypeForLiteral(ty))
821 }
822}
823
824pub fn try_extract_nz_wrapped_type(db: &dyn SemanticGroup, ty: TypeId) -> Option<TypeId> {
826 let concrete_ty = try_extract_matches!(ty.lookup_intern(db), TypeLongId::Concrete)?;
827 let extern_ty = try_extract_matches!(concrete_ty, ConcreteTypeId::Extern)?;
828 let ConcreteExternTypeLongId { extern_type_id, generic_args } = extern_ty.lookup_intern(db);
829 let [GenericArgumentId::Type(inner)] = generic_args[..] else { return None };
830 (extern_type_id.name(db.upcast()) == "NonZero").then_some(inner)
831}
832
833fn try_extract_bounded_int_type_ranges(
835 db: &dyn SemanticGroup,
836 ty: TypeId,
837) -> Option<(BigInt, BigInt)> {
838 let concrete_ty = try_extract_matches!(db.lookup_intern_type(ty), TypeLongId::Concrete)?;
839 let extern_ty = try_extract_matches!(concrete_ty, ConcreteTypeId::Extern)?;
840 let ConcreteExternTypeLongId { extern_type_id, generic_args } =
841 db.lookup_intern_concrete_extern_type(extern_ty);
842 require(extern_type_id.name(db.upcast()) == "BoundedInt")?;
843 let [GenericArgumentId::Constant(min), GenericArgumentId::Constant(max)] = generic_args[..]
844 else {
845 return None;
846 };
847 let to_int = |id| db.lookup_intern_const_value(id).into_int();
848
849 Some((to_int(min)?, to_int(max)?))
850}
851
852#[derive(Debug, Eq, PartialEq, Hash)]
854pub struct CoreInfo {
855 pub felt252: TypeId,
857 pub u8: TypeId,
858 pub u16: TypeId,
859 pub u32: TypeId,
860 pub u64: TypeId,
861 pub u128: TypeId,
862 pub u256: TypeId,
863 pub i8: TypeId,
864 pub i16: TypeId,
865 pub i32: TypeId,
866 pub i64: TypeId,
867 pub i128: TypeId,
868 pub class_hash: TypeId,
869 pub contract_address: TypeId,
870 pub numeric_literal_trt: TraitId,
872 pub string_literal_trt: TraitId,
873 pub deref_trt: TraitId,
874 pub deref_mut_trt: TraitId,
875 pub index_trt: TraitId,
876 pub index_view_trt: TraitId,
877 pub copy_trt: TraitId,
878 pub drop_trt: TraitId,
879 pub destruct_trt: TraitId,
880 pub panic_destruct_trt: TraitId,
881 pub add_trt: TraitId,
882 pub sub_trt: TraitId,
883 pub mul_trt: TraitId,
884 pub div_trt: TraitId,
885 pub rem_trt: TraitId,
886 pub div_rem_trt: TraitId,
887 pub neg_trt: TraitId,
888 pub add_assign_trt: TraitId,
889 pub sub_assign_trt: TraitId,
890 pub mul_assign_trt: TraitId,
891 pub div_assign_trt: TraitId,
892 pub rem_assign_trt: TraitId,
893 pub bitnot_trt: TraitId,
894 pub bitand_trt: TraitId,
895 pub bitor_trt: TraitId,
896 pub bitxor_trt: TraitId,
897 pub not_trt: TraitId,
898 pub partialeq_trt: TraitId,
899 pub partialord_trt: TraitId,
900 pub range_op_trt: TraitId,
901 pub range_inclusive_op_trt: TraitId,
902 pub into_iterator_trt: TraitId,
903 pub iterator_trt: TraitId,
904 pub fn_trt: TraitId,
905 pub fn_once_trt: TraitId,
906 pub type_eq_trt: TraitId,
907 pub felt252_dict_value_trt: TraitId,
908 pub deref_fn: TraitFunctionId,
910 pub deref_mut_fn: TraitFunctionId,
911 pub destruct_fn: TraitFunctionId,
912 pub panic_destruct_fn: TraitFunctionId,
913 pub add_fn: TraitFunctionId,
914 pub sub_fn: TraitFunctionId,
915 pub mul_fn: TraitFunctionId,
916 pub div_fn: TraitFunctionId,
917 pub rem_fn: TraitFunctionId,
918 pub div_rem_fn: TraitFunctionId,
919 pub neg_fn: TraitFunctionId,
920 pub add_assign_fn: TraitFunctionId,
921 pub sub_assign_fn: TraitFunctionId,
922 pub mul_assign_fn: TraitFunctionId,
923 pub div_assign_fn: TraitFunctionId,
924 pub rem_assign_fn: TraitFunctionId,
925 pub bitnot_fn: TraitFunctionId,
926 pub bitand_fn: TraitFunctionId,
927 pub bitor_fn: TraitFunctionId,
928 pub bitxor_fn: TraitFunctionId,
929 pub not_fn: TraitFunctionId,
930 pub eq_fn: TraitFunctionId,
931 pub ne_fn: TraitFunctionId,
932 pub lt_fn: TraitFunctionId,
933 pub gt_fn: TraitFunctionId,
934 pub le_fn: TraitFunctionId,
935 pub ge_fn: TraitFunctionId,
936 pub range_fn: TraitFunctionId,
937 pub range_inclusive_fn: TraitFunctionId,
938 pub into_iter_fn: TraitFunctionId,
939 pub next_fn: TraitFunctionId,
940 pub call_fn: TraitFunctionId,
941 pub call_once_fn: TraitFunctionId,
942}
943impl CoreInfo {
944 fn new(db: &dyn SemanticGroup) -> Self {
945 let core = ModuleHelper::core(db);
946 let integer = core.submodule("integer");
947 let traits = core.submodule("traits");
948 let ops = core.submodule("ops");
949 let deref_module = ops.submodule("deref");
950 let deref_trt = deref_module.trait_id("Deref");
951 let deref_mut_trt = deref_module.trait_id("DerefMut");
952 let destruct_trt = traits.trait_id("Destruct");
953 let panic_destruct_trt = traits.trait_id("PanicDestruct");
954 let add_trt = traits.trait_id("Add");
955 let sub_trt = traits.trait_id("Sub");
956 let mul_trt = traits.trait_id("Mul");
957 let div_trt = traits.trait_id("Div");
958 let rem_trt = traits.trait_id("Rem");
959 let div_rem_trt = traits.trait_id("DivRem");
960 let neg_trt = traits.trait_id("Neg");
961 let arith_module = ops.submodule("arith");
962 let add_assign_trt = arith_module.trait_id("AddAssign");
963 let sub_assign_trt = arith_module.trait_id("SubAssign");
964 let mul_assign_trt = arith_module.trait_id("MulAssign");
965 let div_assign_trt = arith_module.trait_id("DivAssign");
966 let rem_assign_trt = arith_module.trait_id("RemAssign");
967 let bitnot_trt = traits.trait_id("BitNot");
968 let bitand_trt = traits.trait_id("BitAnd");
969 let bitor_trt = traits.trait_id("BitOr");
970 let bitxor_trt = traits.trait_id("BitXor");
971 let not_trt = traits.trait_id("Not");
972 let partialeq_trt = traits.trait_id("PartialEq");
973 let partialord_trt = traits.trait_id("PartialOrd");
974 let range_module = ops.submodule("range");
975 let range_op_trt = range_module.trait_id("RangeOp");
976 let range_inclusive_op_trt = range_module.trait_id("RangeInclusiveOp");
977 let iter_traits = core.submodule("iter").submodule("traits");
978 let into_iterator_trt = iter_traits.submodule("collect").trait_id("IntoIterator");
979 let iterator_trt = iter_traits.submodule("iterator").trait_id("Iterator");
980 let fn_module = ops.submodule("function");
981 let fn_trt = fn_module.trait_id("Fn");
982 let fn_once_trt = fn_module.trait_id("FnOnce");
983 let index_module = ops.submodule("index");
984 let starknet = core.submodule("starknet");
985 let trait_fn = |trait_id: TraitId, name: &str| {
986 db.trait_function_by_name(trait_id, name.into()).unwrap().unwrap()
987 };
988 Self {
989 felt252: core.ty("felt252", vec![]),
990 u8: integer.ty("u8", vec![]),
991 u16: integer.ty("u16", vec![]),
992 u32: integer.ty("u32", vec![]),
993 u64: integer.ty("u64", vec![]),
994 u128: integer.ty("u128", vec![]),
995 u256: integer.ty("u256", vec![]),
996 i8: integer.ty("i8", vec![]),
997 i16: integer.ty("i16", vec![]),
998 i32: integer.ty("i32", vec![]),
999 i64: integer.ty("i64", vec![]),
1000 i128: integer.ty("i128", vec![]),
1001 class_hash: starknet.submodule("class_hash").ty("ClassHash", vec![]),
1002 contract_address: starknet.submodule("contract_address").ty("ContractAddress", vec![]),
1003 numeric_literal_trt: integer.trait_id("NumericLiteral"),
1004 string_literal_trt: core.submodule("string").trait_id("StringLiteral"),
1005 index_trt: index_module.trait_id("Index"),
1006 index_view_trt: index_module.trait_id("IndexView"),
1007 deref_trt,
1008 deref_mut_trt,
1009 copy_trt: traits.trait_id("Copy"),
1010 drop_trt: traits.trait_id("Drop"),
1011 destruct_trt,
1012 panic_destruct_trt,
1013 add_trt,
1014 sub_trt,
1015 mul_trt,
1016 div_trt,
1017 rem_trt,
1018 div_rem_trt,
1019 neg_trt,
1020 add_assign_trt,
1021 sub_assign_trt,
1022 mul_assign_trt,
1023 div_assign_trt,
1024 rem_assign_trt,
1025 bitnot_trt,
1026 bitand_trt,
1027 bitor_trt,
1028 bitxor_trt,
1029 not_trt,
1030 partialeq_trt,
1031 partialord_trt,
1032 range_op_trt,
1033 range_inclusive_op_trt,
1034 into_iterator_trt,
1035 iterator_trt,
1036 fn_trt,
1037 fn_once_trt,
1038 type_eq_trt: core.submodule("metaprogramming").trait_id("TypeEqual"),
1039 felt252_dict_value_trt: traits.trait_id("Felt252DictValue"),
1040 deref_fn: trait_fn(deref_trt, "deref"),
1041 deref_mut_fn: trait_fn(deref_mut_trt, "deref_mut"),
1042 destruct_fn: trait_fn(destruct_trt, "destruct"),
1043 panic_destruct_fn: trait_fn(panic_destruct_trt, "panic_destruct"),
1044 add_fn: trait_fn(add_trt, "add"),
1045 sub_fn: trait_fn(sub_trt, "sub"),
1046 mul_fn: trait_fn(mul_trt, "mul"),
1047 div_fn: trait_fn(div_trt, "div"),
1048 rem_fn: trait_fn(rem_trt, "rem"),
1049 div_rem_fn: trait_fn(div_rem_trt, "div_rem"),
1050 neg_fn: trait_fn(neg_trt, "neg"),
1051 add_assign_fn: trait_fn(add_assign_trt, "add_assign"),
1052 sub_assign_fn: trait_fn(sub_assign_trt, "sub_assign"),
1053 mul_assign_fn: trait_fn(mul_assign_trt, "mul_assign"),
1054 div_assign_fn: trait_fn(div_assign_trt, "div_assign"),
1055 rem_assign_fn: trait_fn(rem_assign_trt, "rem_assign"),
1056 bitnot_fn: trait_fn(bitnot_trt, "bitnot"),
1057 bitand_fn: trait_fn(bitand_trt, "bitand"),
1058 bitor_fn: trait_fn(bitor_trt, "bitor"),
1059 bitxor_fn: trait_fn(bitxor_trt, "bitxor"),
1060 not_fn: trait_fn(not_trt, "not"),
1061 eq_fn: trait_fn(partialeq_trt, "eq"),
1062 ne_fn: trait_fn(partialeq_trt, "ne"),
1063 lt_fn: trait_fn(partialord_trt, "lt"),
1064 gt_fn: trait_fn(partialord_trt, "gt"),
1065 le_fn: trait_fn(partialord_trt, "le"),
1066 ge_fn: trait_fn(partialord_trt, "ge"),
1067 range_fn: trait_fn(range_op_trt, "range"),
1068 range_inclusive_fn: trait_fn(range_inclusive_op_trt, "range_inclusive"),
1069 into_iter_fn: trait_fn(into_iterator_trt, "into_iter"),
1070 next_fn: trait_fn(iterator_trt, "next"),
1071 call_fn: trait_fn(fn_trt, "call"),
1072 call_once_fn: trait_fn(fn_once_trt, "call"),
1073 }
1074 }
1075}
1076
1077pub fn core_info(db: &dyn SemanticGroup) -> Arc<CoreInfo> {
1079 CoreInfo::new(db).into()
1080}