Skip to main content

cairo_lang_semantic/
corelib.rs

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