1use cairo_lang_defs::ids::{
2 EnumId, GenericTypeId, ImplDefId, ModuleId, ModuleItemId, NamedLanguageElementId,
3 TraitFunctionId, TraitId,
4};
5use cairo_lang_diagnostics::{Maybe, ToOption};
6use cairo_lang_filesystem::ids::CrateId;
7use cairo_lang_syntax::node::Terminal;
8use cairo_lang_syntax::node::ast::{self, BinaryOperator, UnaryOperator};
9use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
10use cairo_lang_utils::{
11 Intern, LookupIntern, OptionFrom, extract_matches, require, try_extract_matches,
12};
13use num_bigint::BigInt;
14use num_traits::{Num, Signed, ToPrimitive, Zero};
15use smol_str::SmolStr;
16
17use crate::db::SemanticGroup;
18use crate::diagnostic::SemanticDiagnosticKind;
19use crate::expr::compute::ComputationContext;
20use crate::expr::inference::Inference;
21use crate::items::constant::ConstValue;
22use crate::items::enm::SemanticEnumEx;
23use crate::items::functions::{GenericFunctionId, ImplGenericFunctionId};
24use crate::items::imp::ImplLongId;
25use crate::items::trt::{
26 ConcreteTraitGenericFunctionId, ConcreteTraitGenericFunctionLongId, ConcreteTraitId,
27};
28use crate::items::us::SemanticUseEx;
29use crate::resolve::ResolvedGenericItem;
30use crate::types::{ConcreteEnumLongId, ConcreteExternTypeLongId};
31use crate::{
32 ConcreteEnumId, ConcreteFunction, ConcreteImplLongId, ConcreteTypeId, ConcreteVariant, Expr,
33 ExprId, ExprTuple, FunctionId, FunctionLongId, GenericArgumentId, TypeId, TypeLongId, semantic,
34};
35
36pub fn core_module(db: &dyn SemanticGroup) -> ModuleId {
37 let core_crate = db.core_crate();
38 ModuleId::CrateRoot(core_crate)
39}
40
41pub fn get_submodule(
43 db: &dyn SemanticGroup,
44 base_module: ModuleId,
45 submodule_name: &str,
46) -> Option<ModuleId> {
47 let submodules = db.module_submodules(base_module).ok()?;
48 let syntax_db = db.upcast();
49 for (submodule_id, submodule) in submodules.iter() {
50 if submodule.name(syntax_db).text(syntax_db) == submodule_name {
51 return Some(ModuleId::Submodule(*submodule_id));
52 }
53 }
54 None
55}
56
57pub fn core_submodule(db: &dyn SemanticGroup, submodule_name: &str) -> ModuleId {
60 get_submodule(db, core_module(db), submodule_name)
61 .unwrap_or_else(|| panic!("`{submodule_name}` is not a core submodule."))
62}
63
64pub fn core_crate(db: &dyn SemanticGroup) -> CrateId {
65 CrateId::core(db)
66}
67
68pub fn core_felt252_ty(db: &dyn SemanticGroup) -> TypeId {
69 get_core_ty_by_name(db, "felt252".into(), vec![])
70}
71
72pub fn bounded_int_ty(db: &dyn SemanticGroup, min: BigInt, max: BigInt) -> TypeId {
74 let internal = core_submodule(db, "internal");
75 let bounded_int = get_submodule(db, internal, "bounded_int")
76 .expect("Could not find bounded_int submodule in corelib.");
77 let size_ty = db.core_felt252_ty();
78 let lower_id = ConstValue::Int(min, size_ty).intern(db);
79 let upper_id = ConstValue::Int(max, size_ty).intern(db);
80 try_get_ty_by_name(db, bounded_int, "BoundedInt".into(), vec![
81 GenericArgumentId::Constant(lower_id),
82 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(db, core_submodule(db, "zeroable"), "NonZero".into(), vec![
89 GenericArgumentId::Type(inner_type),
90 ])
91}
92
93pub fn core_result_ty(db: &dyn SemanticGroup, ok_type: TypeId, err_type: TypeId) -> TypeId {
94 get_ty_by_name(db, core_submodule(db, "result"), "Result".into(), vec![
95 GenericArgumentId::Type(ok_type),
96 GenericArgumentId::Type(err_type),
97 ])
98}
99
100pub fn core_option_ty(db: &dyn SemanticGroup, some_type: TypeId) -> TypeId {
101 get_ty_by_name(db, core_submodule(db, "option"), "Option".into(), vec![
102 GenericArgumentId::Type(some_type),
103 ])
104}
105
106pub fn core_box_ty(db: &dyn SemanticGroup, inner_type: TypeId) -> TypeId {
107 get_ty_by_name(db, core_submodule(db, "box"), "Box".into(), vec![GenericArgumentId::Type(
108 inner_type,
109 )])
110}
111
112pub fn core_array_felt252_ty(db: &dyn SemanticGroup) -> TypeId {
113 get_core_ty_by_name(db, "Array".into(), vec![GenericArgumentId::Type(db.core_felt252_ty())])
114}
115
116pub fn try_get_core_ty_by_name(
117 db: &dyn SemanticGroup,
118 name: SmolStr,
119 generic_args: Vec<GenericArgumentId>,
120) -> Result<TypeId, SemanticDiagnosticKind> {
121 try_get_ty_by_name(db, db.core_module(), name, generic_args)
122}
123
124pub fn try_get_ty_by_name(
125 db: &dyn SemanticGroup,
126 module: ModuleId,
127 name: SmolStr,
128 generic_args: Vec<GenericArgumentId>,
129) -> Result<TypeId, SemanticDiagnosticKind> {
130 let module_item_id = db
132 .module_item_by_name(module, name.clone())
133 .map_err(|_| SemanticDiagnosticKind::UnknownType)?
134 .ok_or(SemanticDiagnosticKind::UnknownType)?;
135 let generic_type = match module_item_id {
136 ModuleItemId::Use(use_id) => {
137 db.use_resolved_item(use_id).to_option().and_then(|resolved_generic_item| {
138 try_extract_matches!(resolved_generic_item, ResolvedGenericItem::GenericType)
139 })
140 }
141 ModuleItemId::TypeAlias(module_type_alias_id) => {
142 let ty = db
143 .module_type_alias_resolved_type(module_type_alias_id)
144 .expect("Could not find type alias.");
145 assert!(
146 db.module_type_alias_generic_params(module_type_alias_id).unwrap().is_empty(),
147 "Cannot get type aliases with params from corelib."
148 );
149 return Ok(ty);
150 }
151 _ => GenericTypeId::option_from(module_item_id),
152 }
153 .unwrap_or_else(|| panic!("{name} is not a type."));
154
155 Ok(semantic::TypeLongId::Concrete(semantic::ConcreteTypeId::new(
156 db,
157 generic_type,
158 generic_args,
159 ))
160 .intern(db))
161}
162
163pub fn get_core_ty_by_name(
164 db: &dyn SemanticGroup,
165 name: SmolStr,
166 generic_args: Vec<GenericArgumentId>,
167) -> TypeId {
168 try_get_core_ty_by_name(db, name, generic_args).unwrap()
169}
170
171pub fn get_ty_by_name(
172 db: &dyn SemanticGroup,
173 module: ModuleId,
174 name: SmolStr,
175 generic_args: Vec<GenericArgumentId>,
176) -> TypeId {
177 try_get_ty_by_name(db, module, name, generic_args).unwrap()
178}
179
180pub fn core_bool_ty(db: &dyn SemanticGroup) -> TypeId {
181 let core_module = db.core_module();
182 let generic_type = db
184 .module_item_by_name(core_module, "bool".into())
185 .expect("Failed to load core lib.")
186 .and_then(GenericTypeId::option_from)
187 .expect("Type bool was not found in core lib.");
188 semantic::TypeLongId::Concrete(semantic::ConcreteTypeId::new(db, generic_type, vec![]))
189 .intern(db)
190}
191
192pub fn core_bool_enum(db: &dyn SemanticGroup) -> ConcreteEnumId {
195 let core_module = db.core_module();
196 let enum_id = db
198 .module_item_by_name(core_module, "bool".into())
199 .expect("Failed to load core lib.")
200 .and_then(EnumId::option_from)
201 .expect("Type bool was not found in core lib.");
202 ConcreteEnumLongId { enum_id, generic_args: vec![] }.intern(db)
203}
204
205pub fn false_variant(db: &dyn SemanticGroup) -> ConcreteVariant {
207 get_core_enum_concrete_variant(db, "bool", vec![], "False")
208}
209
210pub fn true_variant(db: &dyn SemanticGroup) -> ConcreteVariant {
212 get_core_enum_concrete_variant(db, "bool", vec![], "True")
213}
214
215pub fn jump_nz_zero_variant(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteVariant {
217 get_enum_concrete_variant(
218 db,
219 core_submodule(db, "zeroable"),
220 "IsZeroResult",
221 vec![GenericArgumentId::Type(ty)],
222 "Zero",
223 )
224}
225
226pub fn jump_nz_nonzero_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 "NonZero",
234 )
235}
236
237pub fn option_some_variant(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteVariant {
239 get_enum_concrete_variant(
240 db,
241 core_submodule(db, "option"),
242 "Option",
243 vec![GenericArgumentId::Type(ty)],
244 "Some",
245 )
246}
247
248pub fn option_none_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 "None",
256 )
257}
258
259pub fn false_literal_expr(
262 ctx: &mut ComputationContext<'_>,
263 stable_ptr: ast::ExprPtr,
264) -> semantic::Expr {
265 get_bool_variant_expr(ctx, "bool", "False", stable_ptr)
266}
267
268pub fn true_literal_expr(
271 ctx: &mut ComputationContext<'_>,
272 stable_ptr: ast::ExprPtr,
273) -> semantic::Expr {
274 get_bool_variant_expr(ctx, "bool", "True", stable_ptr)
275}
276
277fn get_bool_variant_expr(
280 ctx: &mut ComputationContext<'_>,
281 enum_name: &str,
282 variant_name: &str,
283 stable_ptr: ast::ExprPtr,
284) -> semantic::Expr {
285 let concrete_variant = get_core_enum_concrete_variant(ctx.db, enum_name, vec![], variant_name);
286 semantic::Expr::EnumVariantCtor(semantic::ExprEnumVariantCtor {
287 variant: concrete_variant,
288 value_expr: unit_expr(ctx, stable_ptr),
289 ty: core_bool_ty(ctx.db),
290 stable_ptr,
291 })
292}
293
294pub fn get_enum_concrete_variant(
297 db: &dyn SemanticGroup,
298 module_id: ModuleId,
299 enum_name: &str,
300 generic_args: Vec<GenericArgumentId>,
301 variant_name: &str,
302) -> ConcreteVariant {
303 let ty = get_ty_by_name(db, module_id, enum_name.into(), generic_args);
304 let concrete_ty = extract_matches!(ty.lookup_intern(db), TypeLongId::Concrete);
305 let concrete_enum_id = extract_matches!(concrete_ty, ConcreteTypeId::Enum);
306 let enum_id = concrete_enum_id.enum_id(db);
307 let variant_id = db.enum_variants(enum_id).unwrap()[variant_name];
308 let variant = db.variant_semantic(enum_id, variant_id).unwrap();
309 db.concrete_enum_variant(concrete_enum_id, &variant).unwrap()
310}
311
312pub fn get_core_enum_concrete_variant(
315 db: &dyn SemanticGroup,
316 enum_name: &str,
317 generic_args: Vec<GenericArgumentId>,
318 variant_name: &str,
319) -> ConcreteVariant {
320 get_enum_concrete_variant(db, core_module(db), enum_name, generic_args, variant_name)
321}
322
323pub fn unit_ty(db: &dyn SemanticGroup) -> TypeId {
325 semantic::TypeLongId::Tuple(vec![]).intern(db)
326}
327
328pub fn never_ty(db: &dyn SemanticGroup) -> TypeId {
330 let core_module = db.core_module();
331 let generic_type = db
333 .module_item_by_name(core_module, "never".into())
334 .expect("Failed to load core lib.")
335 .and_then(GenericTypeId::option_from)
336 .expect("Type bool was not found in core lib.");
337 semantic::TypeLongId::Concrete(semantic::ConcreteTypeId::new(db, generic_type, vec![]))
338 .intern(db)
339}
340
341pub enum ErrorPropagationType {
342 Option { some_variant: ConcreteVariant, none_variant: ConcreteVariant },
343 Result { ok_variant: ConcreteVariant, err_variant: ConcreteVariant },
344}
345impl ErrorPropagationType {
346 pub fn ok_variant(&self) -> &ConcreteVariant {
347 match self {
348 ErrorPropagationType::Option { some_variant, .. } => some_variant,
349 ErrorPropagationType::Result { ok_variant, .. } => ok_variant,
350 }
351 }
352 pub fn err_variant(&self) -> &ConcreteVariant {
353 match self {
354 ErrorPropagationType::Option { none_variant, .. } => none_variant,
355 ErrorPropagationType::Result { err_variant, .. } => err_variant,
356 }
357 }
358}
359
360pub fn unwrap_error_propagation_type(
363 db: &dyn SemanticGroup,
364 ty: TypeId,
365) -> Option<ErrorPropagationType> {
366 match ty.lookup_intern(db) {
367 TypeLongId::Concrete(semantic::ConcreteTypeId::Enum(enm)) => {
369 if let [ok_variant, err_variant] =
370 db.concrete_enum_variants(enm).to_option()?.as_slice()
371 {
372 let name = enm.enum_id(db.upcast()).name(db.upcast());
373 if name == "Option" {
374 return Some(ErrorPropagationType::Option {
375 some_variant: ok_variant.clone(),
376 none_variant: err_variant.clone(),
377 });
378 } else if name == "Result" {
379 return Some(ErrorPropagationType::Result {
380 ok_variant: ok_variant.clone(),
381 err_variant: err_variant.clone(),
382 });
383 }
384 }
385 None
386 }
387 TypeLongId::GenericParameter(_) => todo!(
388 "When generic types are supported, if type is of matching type, allow unwrapping it \
389 to type."
390 ),
391 TypeLongId::Concrete(
392 semantic::ConcreteTypeId::Struct(_) | semantic::ConcreteTypeId::Extern(_),
393 )
394 | TypeLongId::Tuple(_)
395 | TypeLongId::Snapshot(_)
396 | TypeLongId::Var(_)
397 | TypeLongId::Coupon(_)
398 | TypeLongId::ImplType(_)
399 | TypeLongId::Missing(_)
400 | TypeLongId::FixedSizeArray { .. }
401 | TypeLongId::Closure(_) => None,
402 TypeLongId::TraitType(_) => {
404 panic!("Trait types should only appear in traits, where there are no function bodies.")
405 }
406 }
407}
408
409pub fn unit_expr(ctx: &mut ComputationContext<'_>, stable_ptr: ast::ExprPtr) -> ExprId {
412 ctx.arenas.exprs.alloc(Expr::Tuple(ExprTuple {
413 items: Vec::new(),
414 ty: TypeLongId::Tuple(Vec::new()).intern(ctx.db),
415 stable_ptr,
416 }))
417}
418
419pub fn core_unary_operator(
420 db: &dyn SemanticGroup,
421 inference: &mut Inference<'_>,
422 unary_op: &UnaryOperator,
423 stable_ptr: SyntaxStablePtrId,
424) -> Maybe<Result<ConcreteTraitGenericFunctionId, SemanticDiagnosticKind>> {
425 let (trait_name, function_name) = match unary_op {
426 UnaryOperator::Minus(_) => ("Neg", "neg"),
427 UnaryOperator::Not(_) => ("Not", "not"),
428 UnaryOperator::BitNot(_) => ("BitNot", "bitnot"),
429 UnaryOperator::At(_) => unreachable!("@ is not an unary operator."),
430 UnaryOperator::Desnap(_) => unreachable!("* is not an unary operator."),
431 };
432 Ok(Ok(get_core_trait_function_infer(
433 db,
434 inference,
435 CoreTraitContext::TopLevel,
436 trait_name.into(),
437 function_name.into(),
438 stable_ptr,
439 )))
440}
441
442pub fn core_binary_operator(
443 db: &dyn SemanticGroup,
444 inference: &mut Inference<'_>,
445 binary_op: &BinaryOperator,
446 stable_ptr: SyntaxStablePtrId,
447) -> Maybe<Result<(ConcreteTraitGenericFunctionId, bool), SemanticDiagnosticKind>> {
448 let (trait_name, function_name, snapshot, context) = match binary_op {
449 BinaryOperator::Plus(_) => ("Add", "add", false, CoreTraitContext::TopLevel),
450 BinaryOperator::PlusEq(_) => ("AddAssign", "add_assign", false, CoreTraitContext::Ops),
451 BinaryOperator::Minus(_) => ("Sub", "sub", false, CoreTraitContext::TopLevel),
452 BinaryOperator::MinusEq(_) => ("SubAssign", "sub_assign", false, CoreTraitContext::Ops),
453 BinaryOperator::Mul(_) => ("Mul", "mul", false, CoreTraitContext::TopLevel),
454 BinaryOperator::MulEq(_) => ("MulAssign", "mul_assign", false, CoreTraitContext::Ops),
455 BinaryOperator::Div(_) => ("Div", "div", false, CoreTraitContext::TopLevel),
456 BinaryOperator::DivEq(_) => ("DivAssign", "div_assign", false, CoreTraitContext::Ops),
457 BinaryOperator::Mod(_) => ("Rem", "rem", false, CoreTraitContext::TopLevel),
458 BinaryOperator::ModEq(_) => ("RemAssign", "rem_assign", false, CoreTraitContext::Ops),
459 BinaryOperator::EqEq(_) => ("PartialEq", "eq", true, CoreTraitContext::TopLevel),
460 BinaryOperator::Neq(_) => ("PartialEq", "ne", true, CoreTraitContext::TopLevel),
461 BinaryOperator::LE(_) => ("PartialOrd", "le", false, CoreTraitContext::TopLevel),
462 BinaryOperator::GE(_) => ("PartialOrd", "ge", false, CoreTraitContext::TopLevel),
463 BinaryOperator::LT(_) => ("PartialOrd", "lt", false, CoreTraitContext::TopLevel),
464 BinaryOperator::GT(_) => ("PartialOrd", "gt", false, CoreTraitContext::TopLevel),
465 BinaryOperator::And(_) => ("BitAnd", "bitand", false, CoreTraitContext::TopLevel),
466 BinaryOperator::Or(_) => ("BitOr", "bitor", false, CoreTraitContext::TopLevel),
467 BinaryOperator::Xor(_) => ("BitXor", "bitxor", false, CoreTraitContext::TopLevel),
468 BinaryOperator::DotDot(_) => ("RangeOp", "range", false, CoreTraitContext::Ops),
469 _ => return Ok(Err(SemanticDiagnosticKind::UnknownBinaryOperator)),
470 };
471 Ok(Ok((
472 get_core_trait_function_infer(
473 db,
474 inference,
475 context,
476 trait_name.into(),
477 function_name.into(),
478 stable_ptr,
479 ),
480 snapshot,
481 )))
482}
483
484pub fn felt252_eq(db: &dyn SemanticGroup) -> FunctionId {
485 get_core_function_impl_method(db, "Felt252PartialEq".into(), "eq".into())
486}
487
488pub fn felt252_sub(db: &dyn SemanticGroup) -> FunctionId {
489 get_core_function_impl_method(db, "Felt252Sub".into(), "sub".into())
490}
491
492fn get_core_function_impl_method(
494 db: &dyn SemanticGroup,
495 impl_name: SmolStr,
496 method_name: SmolStr,
497) -> FunctionId {
498 let core_module = db.core_module();
499 let module_item_id = db
500 .module_item_by_name(core_module, impl_name.clone())
501 .expect("Failed to load core lib.")
502 .unwrap_or_else(|| panic!("Impl '{impl_name}' was not found in core lib."));
503 let impl_def_id = match module_item_id {
504 ModuleItemId::Use(use_id) => {
505 db.use_resolved_item(use_id).to_option().and_then(|resolved_generic_item| {
506 try_extract_matches!(resolved_generic_item, ResolvedGenericItem::Impl)
507 })
508 }
509 _ => ImplDefId::option_from(module_item_id),
510 }
511 .unwrap_or_else(|| panic!("{impl_name} is not an impl."));
512 let impl_id =
513 ImplLongId::Concrete(ConcreteImplLongId { impl_def_id, generic_args: vec![] }.intern(db))
514 .intern(db);
515 let concrete_trait_id = db.impl_concrete_trait(impl_id).unwrap();
516 let function = db
517 .trait_functions(concrete_trait_id.trait_id(db))
518 .ok()
519 .and_then(|functions| functions.get(&method_name).cloned())
520 .unwrap_or_else(|| {
521 panic!("no {method_name} in {}.", concrete_trait_id.trait_id(db).name(db.upcast()))
522 });
523 FunctionLongId {
524 function: ConcreteFunction {
525 generic_function: GenericFunctionId::Impl(ImplGenericFunctionId { impl_id, function }),
526 generic_args: vec![],
527 },
528 }
529 .intern(db)
530}
531
532pub fn core_felt252_is_zero(db: &dyn SemanticGroup) -> FunctionId {
533 get_core_function_id(db, "felt252_is_zero".into(), vec![])
534}
535
536pub fn core_withdraw_gas_fns(db: &dyn SemanticGroup) -> [FunctionId; 2] {
538 let gas = core_submodule(db, "gas");
539 [
540 get_function_id(db, gas, "withdraw_gas".into(), vec![]),
541 get_function_id(db, gas, "withdraw_gas_all".into(), vec![]),
542 ]
543}
544
545pub fn internal_require_implicit(db: &dyn SemanticGroup) -> GenericFunctionId {
546 get_generic_function_id(db, core_submodule(db, "internal"), "require_implicit".into())
547}
548pub fn core_downcast(db: &dyn SemanticGroup, input: TypeId, output: TypeId) -> FunctionId {
550 let internal = core_submodule(db, "integer");
551
552 get_function_id(db, internal, "downcast".into(), vec![
553 GenericArgumentId::Type(input),
554 GenericArgumentId::Type(output),
555 ])
556}
557pub fn get_core_function_id(
559 db: &dyn SemanticGroup,
560 name: SmolStr,
561 generic_args: Vec<GenericArgumentId>,
562) -> FunctionId {
563 get_function_id(db, db.core_module(), name, generic_args)
564}
565
566pub fn get_function_id(
568 db: &dyn SemanticGroup,
569 module: ModuleId,
570 name: SmolStr,
571 generic_args: Vec<GenericArgumentId>,
572) -> FunctionId {
573 let generic_function = get_generic_function_id(db, module, name);
574
575 FunctionLongId { function: ConcreteFunction { generic_function, generic_args } }.intern(db)
576}
577
578pub fn get_core_generic_function_id(db: &dyn SemanticGroup, name: SmolStr) -> GenericFunctionId {
580 get_generic_function_id(db, db.core_module(), name)
581}
582
583pub fn get_generic_function_id(
585 db: &dyn SemanticGroup,
586 module: ModuleId,
587 name: SmolStr,
588) -> GenericFunctionId {
589 let module_item_id = db
590 .module_item_by_name(module, name.clone())
591 .expect("Failed to load core lib.")
592 .unwrap_or_else(|| panic!("Function '{name}' was not found in core lib."));
593 match module_item_id {
594 ModuleItemId::Use(use_id) => {
595 db.use_resolved_item(use_id).to_option().and_then(|resolved_generic_item| {
596 try_extract_matches!(resolved_generic_item, ResolvedGenericItem::GenericFunction)
597 })
598 }
599 _ => GenericFunctionId::option_from(module_item_id),
600 }
601 .unwrap_or_else(|| panic!("{name} is not a function."))
602}
603
604pub fn concrete_copy_trait(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteTraitId {
605 get_core_concrete_trait(db, "Copy".into(), vec![GenericArgumentId::Type(ty)])
606}
607
608pub fn concrete_drop_trait(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteTraitId {
609 get_core_concrete_trait(db, "Drop".into(), vec![GenericArgumentId::Type(ty)])
610}
611
612pub fn concrete_destruct_trait(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteTraitId {
613 get_core_concrete_trait(db, "Destruct".into(), vec![GenericArgumentId::Type(ty)])
614}
615
616pub fn concrete_panic_destruct_trait(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteTraitId {
617 get_core_concrete_trait(db, "PanicDestruct".into(), vec![GenericArgumentId::Type(ty)])
618}
619
620pub fn concrete_iterator_trait(db: &dyn SemanticGroup, ty: TypeId) -> ConcreteTraitId {
621 let trait_id = get_core_trait(db, CoreTraitContext::Iterator, "Iterator".into());
622 semantic::ConcreteTraitLongId { trait_id, generic_args: vec![GenericArgumentId::Type(ty)] }
623 .intern(db)
624}
625
626pub fn fn_once_trait(db: &dyn SemanticGroup) -> TraitId {
627 get_core_trait(db, CoreTraitContext::Ops, "FnOnce".into())
628}
629
630pub fn fn_trait(db: &dyn SemanticGroup) -> TraitId {
631 get_core_trait(db, CoreTraitContext::Ops, "Fn".into())
632}
633
634pub fn fn_traits(db: &dyn SemanticGroup) -> [TraitId; 2] {
635 [fn_trait(db), fn_once_trait(db)]
636}
637
638pub fn fn_once_call_trait_fn(db: &dyn SemanticGroup) -> TraitFunctionId {
639 get_core_trait_fn(db, CoreTraitContext::Ops, "FnOnce".into(), "call".into())
640}
641
642pub fn fn_call_trait_fn(db: &dyn SemanticGroup) -> TraitFunctionId {
643 get_core_trait_fn(db, CoreTraitContext::Ops, "Fn".into(), "call".into())
644}
645
646pub fn copy_trait(db: &dyn SemanticGroup) -> TraitId {
647 get_core_trait(db, CoreTraitContext::TopLevel, "Copy".into())
648}
649
650pub fn drop_trait(db: &dyn SemanticGroup) -> TraitId {
651 get_core_trait(db, CoreTraitContext::TopLevel, "Drop".into())
652}
653
654pub fn destruct_trait(db: &dyn SemanticGroup) -> TraitId {
655 get_core_trait(db, CoreTraitContext::TopLevel, "Destruct".into())
656}
657
658pub fn panic_destruct_trait(db: &dyn SemanticGroup) -> TraitId {
659 get_core_trait(db, CoreTraitContext::TopLevel, "PanicDestruct".into())
660}
661
662pub fn deref_trait(db: &dyn SemanticGroup) -> TraitId {
663 get_core_trait(db, CoreTraitContext::Ops, "Deref".into())
664}
665
666pub fn deref_mut_trait(db: &dyn SemanticGroup) -> TraitId {
667 get_core_trait(db, CoreTraitContext::Ops, "DerefMut".into())
668}
669
670pub fn destruct_trait_fn(db: &dyn SemanticGroup) -> TraitFunctionId {
671 get_core_trait_fn(db, CoreTraitContext::TopLevel, "Destruct".into(), "destruct".into())
672}
673
674pub fn panic_destruct_trait_fn(db: &dyn SemanticGroup) -> TraitFunctionId {
675 get_core_trait_fn(
676 db,
677 CoreTraitContext::TopLevel,
678 "PanicDestruct".into(),
679 "panic_destruct".into(),
680 )
681}
682
683pub fn into_iterator_trait(db: &dyn SemanticGroup) -> TraitId {
684 get_core_trait(db, CoreTraitContext::Iterator, "IntoIterator".into())
685}
686
687pub fn numeric_literal_trait(db: &dyn SemanticGroup) -> TraitId {
688 get_core_trait(db, CoreTraitContext::TopLevel, "NumericLiteral".into())
689}
690
691fn get_core_concrete_trait(
693 db: &dyn SemanticGroup,
694 name: SmolStr,
695 generic_args: Vec<GenericArgumentId>,
696) -> ConcreteTraitId {
697 let trait_id = get_core_trait(db, CoreTraitContext::TopLevel, name);
698 semantic::ConcreteTraitLongId { trait_id, generic_args }.intern(db)
699}
700
701pub enum CoreTraitContext {
703 TopLevel,
705 Ops,
707 Iterator,
709 MetaProgramming,
711}
712
713pub fn get_core_trait(db: &dyn SemanticGroup, context: CoreTraitContext, name: SmolStr) -> TraitId {
715 let base_module = match context {
716 CoreTraitContext::TopLevel => db.core_module(),
717 CoreTraitContext::Ops => core_submodule(db, "ops"),
718 CoreTraitContext::Iterator => core_submodule(db, "iter"),
719 CoreTraitContext::MetaProgramming => core_submodule(db, "metaprogramming"),
720 };
721 let item_id = db
723 .module_item_by_name(base_module, name.clone())
724 .unwrap_or_else(|_| {
725 panic!(
726 "Core module `{module}` failed to compile.",
727 module = base_module.full_path(db.upcast())
728 )
729 })
730 .unwrap_or_else(|| {
731 panic!(
732 "Core module `{module}` is missing an use item for trait `{name}`.",
733 module = base_module.full_path(db.upcast()),
734 )
735 });
736 match item_id {
737 ModuleItemId::Trait(id) => id,
738 ModuleItemId::Use(use_id) => {
739 extract_matches!(
740 db.use_resolved_item(use_id).unwrap_or_else(|_| panic!(
741 "Could not resolve core trait `{module}::{name}`.",
742 module = base_module.full_path(db.upcast()),
743 )),
744 ResolvedGenericItem::Trait
745 )
746 }
747 _ => panic!("Expecting only traits, or uses pointing to traits."),
748 }
749}
750
751fn get_core_trait_fn(
753 db: &dyn SemanticGroup,
754 context: CoreTraitContext,
755 trait_name: SmolStr,
756 fn_name: SmolStr,
757) -> TraitFunctionId {
758 db.trait_function_by_name(get_core_trait(db, context, trait_name), fn_name).unwrap().unwrap()
759}
760
761fn get_core_trait_function_infer(
764 db: &dyn SemanticGroup,
765 inference: &mut Inference<'_>,
766 context: CoreTraitContext,
767 trait_name: SmolStr,
768 function_name: SmolStr,
769 stable_ptr: SyntaxStablePtrId,
770) -> ConcreteTraitGenericFunctionId {
771 let trait_id = get_core_trait(db, context, trait_name.clone());
772 let generic_params = db.trait_generic_params(trait_id).unwrap();
773 let generic_args = generic_params
774 .iter()
775 .map(|_| GenericArgumentId::Type(inference.new_type_var(Some(stable_ptr))))
776 .collect();
777 let concrete_trait_id = semantic::ConcreteTraitLongId { trait_id, generic_args }.intern(db);
778 let trait_function = db
779 .trait_function_by_name(trait_id, function_name.clone())
780 .unwrap()
781 .unwrap_or_else(move || panic!("Missing function '{function_name}' in '{trait_name}'."));
782 ConcreteTraitGenericFunctionLongId::new(db, concrete_trait_id, trait_function).intern(db)
783}
784
785pub fn get_panic_ty(db: &dyn SemanticGroup, inner_ty: TypeId) -> TypeId {
786 get_core_ty_by_name(db.upcast(), "PanicResult".into(), vec![GenericArgumentId::Type(inner_ty)])
787}
788
789pub fn get_usize_ty(db: &dyn SemanticGroup) -> TypeId {
790 get_core_ty_by_name(db, "usize".into(), vec![])
791}
792
793pub fn get_convert_to_felt252_libfunc_name_by_type(
795 db: &dyn SemanticGroup,
796 ty: TypeId,
797) -> Option<FunctionId> {
798 if ty == get_core_ty_by_name(db, "u8".into(), vec![]) {
799 Some(get_function_id(db, core_submodule(db, "integer"), "u8_to_felt252".into(), vec![]))
800 } else if ty == get_core_ty_by_name(db, "u16".into(), vec![]) {
801 Some(get_function_id(db, core_submodule(db, "integer"), "u16_to_felt252".into(), vec![]))
802 } else if ty == get_core_ty_by_name(db, "u32".into(), vec![]) {
803 Some(get_function_id(db, core_submodule(db, "integer"), "u32_to_felt252".into(), vec![]))
804 } else if ty == get_core_ty_by_name(db, "u64".into(), vec![]) {
805 Some(get_function_id(db, core_submodule(db, "integer"), "u64_to_felt252".into(), vec![]))
806 } else if ty == get_core_ty_by_name(db, "u128".into(), vec![]) {
807 Some(get_function_id(db, core_submodule(db, "integer"), "u128_to_felt252".into(), vec![]))
808 } else if ty == get_core_ty_by_name(db, "i8".into(), vec![]) {
809 Some(get_function_id(db, core_submodule(db, "integer"), "i8_to_felt252".into(), vec![]))
810 } else if ty == get_core_ty_by_name(db, "i16".into(), vec![]) {
811 Some(get_function_id(db, core_submodule(db, "integer"), "i16_to_felt252".into(), vec![]))
812 } else if ty == get_core_ty_by_name(db, "i32".into(), vec![]) {
813 Some(get_function_id(db, core_submodule(db, "integer"), "i32_to_felt252".into(), vec![]))
814 } else if ty == get_core_ty_by_name(db, "i64".into(), vec![]) {
815 Some(get_function_id(db, core_submodule(db, "integer"), "i64_to_felt252".into(), vec![]))
816 } else if ty == get_core_ty_by_name(db, "i128".into(), vec![]) {
817 Some(get_function_id(db, core_submodule(db, "integer"), "i128_to_felt252".into(), vec![]))
818 } else {
819 None
820 }
821}
822
823#[derive(Clone, Debug, Eq, Hash, PartialEq)]
824pub enum LiteralError {
825 InvalidTypeForLiteral(TypeId),
826 OutOfRange(TypeId),
827}
828impl LiteralError {
829 pub fn format(&self, db: &dyn SemanticGroup) -> String {
830 match self {
831 Self::OutOfRange(ty) => format!(
832 "The value does not fit within the range of type {}.",
833 ty.format(db.upcast())
834 ),
835 Self::InvalidTypeForLiteral(ty) => {
836 format!("A numeric literal of type {} cannot be created.", ty.format(db.upcast()))
837 }
838 }
839 }
840}
841
842pub fn validate_literal(
845 db: &dyn SemanticGroup,
846 ty: TypeId,
847 value: BigInt,
848) -> Result<(), LiteralError> {
849 if let Some(nz_wrapped_ty) = try_extract_nz_wrapped_type(db, ty) {
850 return if value.is_zero() {
851 Err(LiteralError::OutOfRange(ty))
852 } else {
853 validate_literal(db, nz_wrapped_ty, value)
854 };
855 }
856 let is_out_of_range = if let Some((min, max)) = try_extract_bounded_int_type_ranges(db, ty) {
857 value < min || value > max
858 } else if ty == db.core_felt252_ty() {
859 value.abs()
860 > BigInt::from_str_radix(
861 "800000000000011000000000000000000000000000000000000000000000000",
862 16,
863 )
864 .unwrap()
865 } else if ty == get_core_ty_by_name(db, "u8".into(), vec![]) {
866 value.to_u8().is_none()
867 } else if ty == get_core_ty_by_name(db, "u16".into(), vec![]) {
868 value.to_u16().is_none()
869 } else if ty == get_core_ty_by_name(db, "u32".into(), vec![]) {
870 value.to_u32().is_none()
871 } else if ty == get_core_ty_by_name(db, "u64".into(), vec![]) {
872 value.to_u64().is_none()
873 } else if ty == get_core_ty_by_name(db, "u128".into(), vec![]) {
874 value.to_u128().is_none()
875 } else if ty == get_core_ty_by_name(db, "u256".into(), vec![]) {
876 value.is_negative() || value.bits() > 256
877 } else if ty == get_core_ty_by_name(db, "i8".into(), vec![]) {
878 value.to_i8().is_none()
879 } else if ty == get_core_ty_by_name(db, "i16".into(), vec![]) {
880 value.to_i16().is_none()
881 } else if ty == get_core_ty_by_name(db, "i32".into(), vec![]) {
882 value.to_i32().is_none()
883 } else if ty == get_core_ty_by_name(db, "i64".into(), vec![]) {
884 value.to_i64().is_none()
885 } else if ty == get_core_ty_by_name(db, "i128".into(), vec![]) {
886 value.to_i128().is_none()
887 } else {
888 return Err(LiteralError::InvalidTypeForLiteral(ty));
889 };
890 if is_out_of_range { Err(LiteralError::OutOfRange(ty)) } else { Ok(()) }
891}
892
893pub fn try_extract_nz_wrapped_type(db: &dyn SemanticGroup, ty: TypeId) -> Option<TypeId> {
895 let concrete_ty = try_extract_matches!(ty.lookup_intern(db), TypeLongId::Concrete)?;
896 let extern_ty = try_extract_matches!(concrete_ty, ConcreteTypeId::Extern)?;
897 let ConcreteExternTypeLongId { extern_type_id, generic_args } = extern_ty.lookup_intern(db);
898 let [GenericArgumentId::Type(inner)] = generic_args[..] else { return None };
899 (extern_type_id.name(db.upcast()) == "NonZero").then_some(inner)
900}
901
902fn try_extract_bounded_int_type_ranges(
904 db: &dyn SemanticGroup,
905 ty: TypeId,
906) -> Option<(BigInt, BigInt)> {
907 let concrete_ty = try_extract_matches!(db.lookup_intern_type(ty), TypeLongId::Concrete)?;
908 let extern_ty = try_extract_matches!(concrete_ty, ConcreteTypeId::Extern)?;
909 let ConcreteExternTypeLongId { extern_type_id, generic_args } =
910 db.lookup_intern_concrete_extern_type(extern_ty);
911 require(extern_type_id.name(db.upcast()) == "BoundedInt")?;
912 let [GenericArgumentId::Constant(min), GenericArgumentId::Constant(max)] = generic_args[..]
913 else {
914 return None;
915 };
916 let to_int = |id| db.lookup_intern_const_value(id).into_int();
917
918 Some((to_int(min)?, to_int(max)?))
919}