cairo_lang_semantic/
corelib.rs

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
38/// Query implementation of [SemanticGroup::core_module].
39pub fn core_module(db: &dyn SemanticGroup) -> ModuleId {
40    let core_crate = db.core_crate();
41    ModuleId::CrateRoot(core_crate)
42}
43
44/// Returns the submodule of `base_module`, named `submodule_name`, if exists.
45pub 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
58/// Returns a submodule of the corelib named `submodule_name`.
59/// If no such submodule exists, panics.
60pub 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
65/// Query implementation of [SemanticGroup::core_crate].
66pub fn core_crate(db: &dyn SemanticGroup) -> CrateId {
67    CrateId::core(db)
68}
69
70/// Returns the concrete type of a bounded int type with a given min and max.
71pub 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    // This should not fail if the corelib is present.
142    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    // This should not fail if the corelib is present.
194    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
203// TODO(spapini): Consider making all these queries for better caching.
204/// Generates a ConcreteEnumId instance for `bool`.
205pub fn core_bool_enum(db: &dyn SemanticGroup) -> ConcreteEnumId {
206    let core_module = db.core_module();
207    // This should not fail if the corelib is present.
208    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
216/// Generates a ConcreteVariant instance for `false`.
217pub fn false_variant(db: &dyn SemanticGroup) -> ConcreteVariant {
218    get_core_enum_concrete_variant(db, "bool", vec![], "False")
219}
220
221/// Generates a ConcreteVariant instance for `true`.
222pub fn true_variant(db: &dyn SemanticGroup) -> ConcreteVariant {
223    get_core_enum_concrete_variant(db, "bool", vec![], "True")
224}
225
226/// Generates a ConcreteVariant instance for `IsZeroResult::<felt252>::Zero`.
227pub 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
237/// Generates a ConcreteVariant instance for `IsZeroResult::<felt252>::NonZero`.
238pub 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
248/// Generates a ConcreteVariant instance for `Option::Some`.
249pub 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
259/// Generates a ConcreteVariant instance for `Option::None`.
260pub 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
270/// Generates a ConcreteVariant instance for `Result::Ok`.
271pub 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
281/// Generates a ConcreteVariant instance for `Result::Err`.
282pub 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
296/// Generates a ConcreteVariant instance for `SignedIntegerResult::InRange`.
297pub 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}
306/// Generates a ConcreteVariant instance for `SignedIntegerResult::Underflow`.
307pub 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}
316/// Generates a ConcreteVariant instance for `SignedIntegerResult::Overflow`.
317pub 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
327/// Gets a semantic expression of the literal `false`. Uses the given `stable_ptr` in the returned
328/// semantic expression.
329pub 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
336/// Gets a semantic expression of the literal `true`. Uses the given `stable_ptr` in the returned
337/// semantic expression.
338pub 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
345/// Gets a semantic expression of the specified bool enum variant. Uses the given `stable_ptr` in
346/// the returned semantic expression.
347fn 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
362/// Gets a [ConcreteVariant] instance for an enum variant, by module and name.
363/// Assumes the variant exists.
364pub 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
380/// Gets a [ConcreteVariant] instance for an enum variant from the core module, by name.
381/// Assumes the variant exists.
382pub 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
391/// Gets the unit type ().
392pub fn unit_ty(db: &dyn SemanticGroup) -> TypeId {
393    semantic::TypeLongId::Tuple(vec![]).intern(db)
394}
395
396/// Gets the never type ().
397pub fn never_ty(db: &dyn SemanticGroup) -> TypeId {
398    let core_module = db.core_module();
399    // This should not fail if the corelib is present.
400    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
428/// Attempts to unwrap error propagation types (Option, Result).
429/// Returns None if not one of these types.
430pub fn unwrap_error_propagation_type(
431    db: &dyn SemanticGroup,
432    ty: TypeId,
433) -> Option<ErrorPropagationType> {
434    match ty.lookup_intern(db) {
435        // Only enums may be `Result` and `Option` types.
436        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
473/// builds a semantic unit expression. This is not necessarily located in the AST, so it is received
474/// as a param.
475pub 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
540/// Given a core library impl name and a method name, returns [FunctionId].
541fn 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
584/// The gas withdrawal functions from the `gas` submodule.
585pub 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}
596/// Given a core library function name and its generic arguments, returns [FunctionId].
597pub 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
605/// Given a module, a library function name and its generic arguments, returns [FunctionId].
606pub 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
615/// Given a core library function name, returns [GenericFunctionId].
616pub fn get_core_generic_function_id(db: &dyn SemanticGroup, name: SmolStr) -> GenericFunctionId {
617    get_generic_function_id(db, db.core_module(), name)
618}
619
620/// Given a module and a library function name, returns [GenericFunctionId].
621pub 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
666/// Given a core library generic trait and its generic arguments, returns [ConcreteTraitId].
667fn 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
675/// Retrieves a trait function from the core library with type variables as generic arguments, to
676/// be inferred later.
677fn 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
701/// Returns if `ty` is a numeric type upcastable to felt252.
702pub 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
736/// Validates that a given type is valid for a literal and that the value fits the range of the
737/// specific type.
738pub 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
793/// Returns the type if the inner value of a `NonZero` type, if it is wrapped in one.
794pub 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
802/// Returns the ranges of a BoundedInt if it is a BoundedInt type.
803pub 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/// Information about various core types and traits.
822#[derive(Debug, Eq, PartialEq, Hash)]
823pub struct CoreInfo {
824    // Types.
825    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    // Traits.
840    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    // Trait fns.
878    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
1051/// Query implementation of [SemanticGroup::core_info].
1052pub fn core_info(db: &dyn SemanticGroup) -> Arc<CoreInfo> {
1053    CoreInfo::new(db).into()
1054}