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