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