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