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 bool 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    };
556    Ok(Ok(get_core_trait_function_infer(db, inference, trait_id, trait_fn, stable_ptr)))
557}
558
559pub fn core_binary_operator<'db>(
560    db: &'db dyn Database,
561    inference: &mut Inference<'db, '_>,
562    binary_op: &BinaryOperator<'db>,
563    stable_ptr: SyntaxStablePtrId<'db>,
564) -> Maybe<Result<(ConcreteTraitGenericFunctionId<'db>, bool), SemanticDiagnosticKind<'db>>> {
565    let info = db.core_info();
566    let (trait_id, trait_fn, snapshot) = match binary_op {
567        BinaryOperator::Plus(_) => (info.add_trt, info.add_fn, false),
568        BinaryOperator::PlusEq(_) => (info.add_assign_trt, info.add_assign_fn, false),
569        BinaryOperator::Minus(_) => (info.sub_trt, info.sub_fn, false),
570        BinaryOperator::MinusEq(_) => (info.sub_assign_trt, info.sub_assign_fn, false),
571        BinaryOperator::Mul(_) => (info.mul_trt, info.mul_fn, false),
572        BinaryOperator::MulEq(_) => (info.mul_assign_trt, info.mul_assign_fn, false),
573        BinaryOperator::Div(_) => (info.div_trt, info.div_fn, false),
574        BinaryOperator::DivEq(_) => (info.div_assign_trt, info.div_assign_fn, false),
575        BinaryOperator::Mod(_) => (info.rem_trt, info.rem_fn, false),
576        BinaryOperator::ModEq(_) => (info.rem_assign_trt, info.rem_assign_fn, false),
577        BinaryOperator::EqEq(_) => (info.partialeq_trt, info.eq_fn, true),
578        BinaryOperator::Neq(_) => (info.partialeq_trt, info.ne_fn, true),
579        BinaryOperator::LE(_) => (info.partialord_trt, info.le_fn, false),
580        BinaryOperator::GE(_) => (info.partialord_trt, info.ge_fn, false),
581        BinaryOperator::LT(_) => (info.partialord_trt, info.lt_fn, false),
582        BinaryOperator::GT(_) => (info.partialord_trt, info.gt_fn, false),
583        BinaryOperator::And(_) => (info.bitand_trt, info.bitand_fn, false),
584        BinaryOperator::Or(_) => (info.bitor_trt, info.bitor_fn, false),
585        BinaryOperator::Xor(_) => (info.bitxor_trt, info.bitxor_fn, false),
586        BinaryOperator::DotDot(_) => (info.range_op_trt, info.range_fn, false),
587        BinaryOperator::DotDotEq(_) => {
588            (info.range_inclusive_op_trt, info.range_inclusive_fn, false)
589        }
590        _ => return Ok(Err(SemanticDiagnosticKind::UnknownBinaryOperator)),
591    };
592    Ok(Ok((get_core_trait_function_infer(db, inference, trait_id, trait_fn, stable_ptr), snapshot)))
593}
594
595pub fn felt252_sub<'db>(db: &'db dyn Database) -> FunctionId<'db> {
596    get_core_function_impl_method(db, SmolStrId::from(db, "Felt252Sub"), SmolStrId::from(db, "sub"))
597}
598
599/// Given a core library impl name and a method name, returns [FunctionId].
600fn get_core_function_impl_method<'db>(
601    db: &'db dyn Database,
602    impl_name: SmolStrId<'db>,
603    method_name: SmolStrId<'db>,
604) -> FunctionId<'db> {
605    let core_module = db.core_module();
606    let module_item_id = db
607        .module_item_by_name(core_module, impl_name)
608        .expect("Failed to load core lib.")
609        .unwrap_or_else(|| panic!("Impl '{}' was not found in core lib.", impl_name.long(db)));
610    let impl_def_id = match module_item_id {
611        ModuleItemId::Use(use_id) => {
612            db.use_resolved_item(use_id).to_option().and_then(|resolved_generic_item| {
613                try_extract_matches!(resolved_generic_item, ResolvedGenericItem::Impl)
614            })
615        }
616        _ => ImplDefId::option_from(module_item_id),
617    }
618    .unwrap_or_else(|| panic!("{} is not an impl.", impl_name.long(db)));
619    let impl_id =
620        ImplLongId::Concrete(ConcreteImplLongId { impl_def_id, generic_args: vec![] }.intern(db))
621            .intern(db);
622    let concrete_trait_id = db.impl_concrete_trait(impl_id).unwrap();
623    let function = db
624        .trait_functions(concrete_trait_id.trait_id(db))
625        .ok()
626        .and_then(|functions| functions.get(&method_name).cloned())
627        .unwrap_or_else(|| {
628            panic!(
629                "no {} in {}.",
630                method_name.long(db),
631                concrete_trait_id.trait_id(db).name(db).long(db)
632            )
633        });
634    FunctionLongId {
635        function: ConcreteFunction {
636            generic_function: GenericFunctionId::Impl(ImplGenericFunctionId { impl_id, function }),
637            generic_args: vec![],
638        },
639    }
640    .intern(db)
641}
642
643pub fn core_felt252_is_zero<'db>(db: &'db dyn Database) -> FunctionId<'db> {
644    get_core_function_id(db, SmolStrId::from(db, "felt252_is_zero"), vec![])
645}
646
647/// The gas withdrawal functions from the `gas` submodule.
648pub fn core_withdraw_gas_fns<'db>(db: &'db dyn Database) -> [FunctionId<'db>; 2] {
649    let gas = core_submodule(db, SmolStrId::from(db, "gas"));
650    [
651        get_function_id(db, gas, SmolStrId::from(db, "withdraw_gas"), vec![]),
652        get_function_id(db, gas, SmolStrId::from(db, "withdraw_gas_all"), vec![]),
653    ]
654}
655
656pub fn internal_require_implicit(db: &dyn Database) -> GenericFunctionId<'_> {
657    get_generic_function_id(
658        db,
659        core_submodule(db, SmolStrId::from(db, "internal")),
660        SmolStrId::from(db, "require_implicit"),
661    )
662}
663/// Given a core library function name and its generic arguments, returns [FunctionId].
664pub fn get_core_function_id<'db>(
665    db: &'db dyn Database,
666    name: SmolStrId<'db>,
667    generic_args: Vec<GenericArgumentId<'db>>,
668) -> FunctionId<'db> {
669    get_function_id(db, db.core_module(), name, generic_args)
670}
671
672/// Given a module, a library function name and its generic arguments, returns [FunctionId].
673pub fn get_function_id<'db>(
674    db: &'db dyn Database,
675    module: ModuleId<'db>,
676    name: SmolStrId<'db>,
677    generic_args: Vec<GenericArgumentId<'db>>,
678) -> FunctionId<'db> {
679    get_generic_function_id(db, module, name).concretize(db, generic_args)
680}
681
682/// Given a core library function name, returns [GenericFunctionId].
683pub fn get_core_generic_function_id<'db>(
684    db: &'db dyn Database,
685    name: SmolStrId<'db>,
686) -> GenericFunctionId<'db> {
687    get_generic_function_id(db, db.core_module(), name)
688}
689
690/// Given a module and a library function name, returns [GenericFunctionId].
691pub fn get_generic_function_id<'db>(
692    db: &'db dyn Database,
693    module: ModuleId<'db>,
694    name: SmolStrId<'db>,
695) -> GenericFunctionId<'db> {
696    let module_item_id = db
697        .module_item_by_name(module, name)
698        .expect("Failed to load core lib.")
699        .unwrap_or_else(|| panic!("Function '{}' was not found in core lib.", name.long(db)));
700    match module_item_id {
701        ModuleItemId::Use(use_id) => {
702            db.use_resolved_item(use_id).to_option().and_then(|resolved_generic_item| {
703                try_extract_matches!(resolved_generic_item, ResolvedGenericItem::GenericFunction)
704            })
705        }
706        _ => GenericFunctionId::option_from(module_item_id),
707    }
708    .unwrap_or_else(|| panic!("{} is not a function.", name.long(db)))
709}
710
711pub fn concrete_copy_trait<'db>(db: &'db dyn Database, ty: TypeId<'db>) -> ConcreteTraitId<'db> {
712    concrete_trait(db, db.core_info().copy_trt, vec![GenericArgumentId::Type(ty)])
713}
714
715pub fn concrete_drop_trait<'db>(db: &'db dyn Database, ty: TypeId<'db>) -> ConcreteTraitId<'db> {
716    concrete_trait(db, db.core_info().drop_trt, vec![GenericArgumentId::Type(ty)])
717}
718
719pub fn concrete_destruct_trait<'db>(
720    db: &'db dyn Database,
721    ty: TypeId<'db>,
722) -> ConcreteTraitId<'db> {
723    concrete_trait(db, db.core_info().destruct_trt, vec![GenericArgumentId::Type(ty)])
724}
725
726pub fn concrete_panic_destruct_trait<'db>(
727    db: &'db dyn Database,
728    ty: TypeId<'db>,
729) -> ConcreteTraitId<'db> {
730    concrete_trait(db, db.core_info().panic_destruct_trt, vec![GenericArgumentId::Type(ty)])
731}
732
733pub fn concrete_iterator_trait<'db>(
734    db: &'db dyn Database,
735    ty: TypeId<'db>,
736) -> ConcreteTraitId<'db> {
737    concrete_trait(db, db.core_info().iterator_trt, vec![GenericArgumentId::Type(ty)])
738}
739
740pub fn fn_traits<'db>(db: &'db dyn Database) -> [TraitId<'db>; 2] {
741    let info = db.core_info();
742    [info.fn_trt, info.fn_once_trt]
743}
744
745/// Given a core library generic trait and its generic arguments, returns [ConcreteTraitId].
746fn concrete_trait<'db>(
747    db: &'db dyn Database,
748    trait_id: TraitId<'db>,
749    generic_args: Vec<GenericArgumentId<'db>>,
750) -> ConcreteTraitId<'db> {
751    semantic::ConcreteTraitLongId { trait_id, generic_args }.intern(db)
752}
753
754/// Retrieves a trait function from the core library with type variables as generic arguments, to
755/// be inferred later.
756fn get_core_trait_function_infer<'db>(
757    db: &'db dyn Database,
758    inference: &mut Inference<'db, '_>,
759    trait_id: TraitId<'db>,
760    trait_function: TraitFunctionId<'db>,
761    stable_ptr: SyntaxStablePtrId<'db>,
762) -> ConcreteTraitGenericFunctionId<'db> {
763    let generic_params = db.trait_generic_params(trait_id).unwrap();
764    let generic_args = generic_params
765        .iter()
766        .map(|_| GenericArgumentId::Type(inference.new_type_var(Some(stable_ptr))))
767        .collect();
768    let concrete_trait_id = semantic::ConcreteTraitLongId { trait_id, generic_args }.intern(db);
769    ConcreteTraitGenericFunctionLongId::new(db, concrete_trait_id, trait_function).intern(db)
770}
771
772pub fn get_panic_ty<'db>(db: &'db dyn Database, inner_ty: TypeId<'db>) -> TypeId<'db> {
773    get_core_ty_by_name(
774        db,
775        SmolStrId::from(db, "PanicResult"),
776        vec![GenericArgumentId::Type(inner_ty)],
777    )
778}
779
780pub fn get_usize_ty<'db>(db: &'db dyn Database) -> TypeId<'db> {
781    get_core_ty_by_name(db, SmolStrId::from(db, "usize"), vec![])
782}
783
784/// Returns if `ty` is a numeric type upcastable to felt252.
785pub fn numeric_upcastable_to_felt252(db: &dyn Database, ty: TypeId<'_>) -> bool {
786    let info = db.core_info();
787    ty == info.felt252
788        || ty == info.u8
789        || ty == info.u16
790        || ty == info.u32
791        || ty == info.u64
792        || ty == info.u128
793        || ty == info.i8
794        || ty == info.i16
795        || ty == info.i32
796        || ty == info.i64
797        || ty == info.i128
798        || try_extract_bounded_int_type_ranges(db, ty).is_some()
799}
800
801#[derive(Clone, Debug, Eq, Hash, PartialEq, salsa::Update)]
802pub enum LiteralError<'db> {
803    InvalidTypeForLiteral(TypeId<'db>),
804    OutOfRange(TypeId<'db>),
805}
806impl<'db> LiteralError<'db> {
807    pub fn format(&self, db: &dyn Database) -> String {
808        match self {
809            Self::OutOfRange(ty) => {
810                format!("The value does not fit within the range of type {}.", ty.format(db))
811            }
812            Self::InvalidTypeForLiteral(ty) => {
813                format!("A numeric literal of type {} cannot be created.", ty.format(db))
814            }
815        }
816    }
817}
818
819/// Validates that a given type is valid for a literal and that the value fits the range of the
820/// specific type.
821pub fn validate_literal<'db>(
822    db: &'db dyn Database,
823    ty: TypeId<'db>,
824    value: &BigInt,
825) -> Result<(), LiteralError<'db>> {
826    let info = db.core_info();
827    let validate_out_of_range = |is_out_of_range: bool| {
828        if is_out_of_range { Err(LiteralError::OutOfRange(ty)) } else { Ok(()) }
829    };
830    if ty == info.felt252 {
831        validate_out_of_range(
832            value.abs()
833                > BigInt::from_str_radix(
834                    "800000000000011000000000000000000000000000000000000000000000000",
835                    16,
836                )
837                .unwrap(),
838        )
839    } else if ty == info.u8 {
840        validate_out_of_range(value.to_u8().is_none())
841    } else if ty == info.u16 {
842        validate_out_of_range(value.to_u16().is_none())
843    } else if ty == info.u32 {
844        validate_out_of_range(value.to_u32().is_none())
845    } else if ty == info.u64 {
846        validate_out_of_range(value.to_u64().is_none())
847    } else if ty == info.u128 {
848        validate_out_of_range(value.to_u128().is_none())
849    } else if ty == info.i8 {
850        validate_out_of_range(value.to_i8().is_none())
851    } else if ty == info.i16 {
852        validate_out_of_range(value.to_i16().is_none())
853    } else if ty == info.i32 {
854        validate_out_of_range(value.to_i32().is_none())
855    } else if ty == info.i64 {
856        validate_out_of_range(value.to_i64().is_none())
857    } else if ty == info.i128 {
858        validate_out_of_range(value.to_i128().is_none())
859    } else if ty == info.u256 {
860        validate_out_of_range(value.is_negative() || value.bits() > 256)
861    } else if ty == info.class_hash || ty == info.contract_address {
862        validate_out_of_range(value.is_negative() || value.bits() > 251)
863    } else if let Some(nz_wrapped_ty) = try_extract_nz_wrapped_type(db, ty) {
864        if value.is_zero() {
865            Err(LiteralError::OutOfRange(ty))
866        } else {
867            validate_literal(db, nz_wrapped_ty, value)
868        }
869    } else if let Some((min, max)) = try_extract_bounded_int_type_ranges(db, ty) {
870        validate_out_of_range(*value < min || *value > max)
871    } else {
872        Err(LiteralError::InvalidTypeForLiteral(ty))
873    }
874}
875
876/// Returns the type if the inner value of a `NonZero` type, if it is wrapped in one.
877pub fn try_extract_nz_wrapped_type<'db>(
878    db: &'db dyn Database,
879    ty: TypeId<'db>,
880) -> Option<TypeId<'db>> {
881    let concrete_ty = try_extract_matches!(ty.long(db), TypeLongId::Concrete)?;
882    let extern_ty = try_extract_matches!(concrete_ty, ConcreteTypeId::Extern)?;
883    let ConcreteExternTypeLongId { extern_type_id, generic_args } = extern_ty.long(db);
884    let [GenericArgumentId::Type(inner)] = generic_args[..] else { return None };
885    (extern_type_id.name(db).long(db) == "NonZero").then_some(inner)
886}
887
888/// Returns the ranges of a BoundedInt if it is a BoundedInt type.
889pub fn try_extract_bounded_int_type_ranges<'db>(
890    db: &'db dyn Database,
891    ty: TypeId<'db>,
892) -> Option<(BigInt, BigInt)> {
893    let concrete_ty = try_extract_matches!(ty.long(db), TypeLongId::Concrete)?;
894    let extern_ty = try_extract_matches!(concrete_ty, ConcreteTypeId::Extern)?;
895    let ConcreteExternTypeLongId { extern_type_id, generic_args } = extern_ty.long(db);
896    require(extern_type_id.name(db).long(db) == "BoundedInt")?;
897    let [GenericArgumentId::Constant(min), GenericArgumentId::Constant(max)] = generic_args[..]
898    else {
899        return None;
900    };
901    let to_int = |id: ConstValueId<'db>| id.long(db).to_int().cloned();
902
903    Some((to_int(min)?, to_int(max)?))
904}
905
906/// Information about various core types and traits.
907#[derive(Debug, Eq, PartialEq, Hash, salsa::Update)]
908pub struct CoreInfo<'db> {
909    // Types.
910    pub felt252: TypeId<'db>,
911    pub u8: TypeId<'db>,
912    pub u16: TypeId<'db>,
913    pub u32: TypeId<'db>,
914    pub u64: TypeId<'db>,
915    pub u128: TypeId<'db>,
916    pub u256: TypeId<'db>,
917    pub i8: TypeId<'db>,
918    pub i16: TypeId<'db>,
919    pub i32: TypeId<'db>,
920    pub i64: TypeId<'db>,
921    pub i128: TypeId<'db>,
922    pub class_hash: TypeId<'db>,
923    pub contract_address: TypeId<'db>,
924    // Traits.
925    pub numeric_literal_trt: TraitId<'db>,
926    pub string_literal_trt: TraitId<'db>,
927    pub deref_trt: TraitId<'db>,
928    pub deref_mut_trt: TraitId<'db>,
929    pub index_trt: TraitId<'db>,
930    pub index_view_trt: TraitId<'db>,
931    pub copy_trt: TraitId<'db>,
932    pub drop_trt: TraitId<'db>,
933    pub destruct_trt: TraitId<'db>,
934    pub panic_destruct_trt: TraitId<'db>,
935    pub add_trt: TraitId<'db>,
936    pub sub_trt: TraitId<'db>,
937    pub mul_trt: TraitId<'db>,
938    pub div_trt: TraitId<'db>,
939    pub rem_trt: TraitId<'db>,
940    pub div_rem_trt: TraitId<'db>,
941    pub neg_trt: TraitId<'db>,
942    pub add_assign_trt: TraitId<'db>,
943    pub sub_assign_trt: TraitId<'db>,
944    pub mul_assign_trt: TraitId<'db>,
945    pub div_assign_trt: TraitId<'db>,
946    pub rem_assign_trt: TraitId<'db>,
947    pub bitnot_trt: TraitId<'db>,
948    pub bitand_trt: TraitId<'db>,
949    pub bitor_trt: TraitId<'db>,
950    pub bitxor_trt: TraitId<'db>,
951    pub not_trt: TraitId<'db>,
952    pub partialeq_trt: TraitId<'db>,
953    pub partialord_trt: TraitId<'db>,
954    pub range_op_trt: TraitId<'db>,
955    pub range_inclusive_op_trt: TraitId<'db>,
956    pub into_iterator_trt: TraitId<'db>,
957    pub iterator_trt: TraitId<'db>,
958    pub fn_trt: TraitId<'db>,
959    pub fn_once_trt: TraitId<'db>,
960    pub type_eq_trt: TraitId<'db>,
961    pub felt252_dict_value_trt: TraitId<'db>,
962    // Trait fns.
963    pub deref_fn: TraitFunctionId<'db>,
964    pub deref_mut_fn: TraitFunctionId<'db>,
965    pub destruct_fn: TraitFunctionId<'db>,
966    pub panic_destruct_fn: TraitFunctionId<'db>,
967    pub add_fn: TraitFunctionId<'db>,
968    pub sub_fn: TraitFunctionId<'db>,
969    pub mul_fn: TraitFunctionId<'db>,
970    pub div_fn: TraitFunctionId<'db>,
971    pub rem_fn: TraitFunctionId<'db>,
972    pub div_rem_fn: TraitFunctionId<'db>,
973    pub neg_fn: TraitFunctionId<'db>,
974    pub add_assign_fn: TraitFunctionId<'db>,
975    pub sub_assign_fn: TraitFunctionId<'db>,
976    pub mul_assign_fn: TraitFunctionId<'db>,
977    pub div_assign_fn: TraitFunctionId<'db>,
978    pub rem_assign_fn: TraitFunctionId<'db>,
979    pub bitnot_fn: TraitFunctionId<'db>,
980    pub bitand_fn: TraitFunctionId<'db>,
981    pub bitor_fn: TraitFunctionId<'db>,
982    pub bitxor_fn: TraitFunctionId<'db>,
983    pub not_fn: TraitFunctionId<'db>,
984    pub eq_fn: TraitFunctionId<'db>,
985    pub ne_fn: TraitFunctionId<'db>,
986    pub lt_fn: TraitFunctionId<'db>,
987    pub gt_fn: TraitFunctionId<'db>,
988    pub le_fn: TraitFunctionId<'db>,
989    pub ge_fn: TraitFunctionId<'db>,
990    pub range_fn: TraitFunctionId<'db>,
991    pub range_inclusive_fn: TraitFunctionId<'db>,
992    pub into_iter_fn: TraitFunctionId<'db>,
993    pub next_fn: TraitFunctionId<'db>,
994    pub call_fn: TraitFunctionId<'db>,
995    pub call_once_fn: TraitFunctionId<'db>,
996    pub upcast_fn: GenericFunctionId<'db>,
997    pub downcast_fn: GenericFunctionId<'db>,
998    pub tuple_submodule: ModuleId<'db>,
999    pub fixed_size_array_submodule: ModuleId<'db>,
1000}
1001impl<'db> CoreInfo<'db> {
1002    fn new(db: &'db dyn Database) -> Self {
1003        let core = ModuleHelper::core(db);
1004        let integer: ModuleHelper<'db> = core.submodule("integer");
1005        let traits = core.submodule("traits");
1006        let ops = core.submodule("ops");
1007        let deref_module = ops.submodule("deref");
1008        let deref_trt = deref_module.trait_id("Deref");
1009        let deref_mut_trt = deref_module.trait_id("DerefMut");
1010        let destruct_trt = traits.trait_id("Destruct");
1011        let panic_destruct_trt = traits.trait_id("PanicDestruct");
1012        let add_trt = traits.trait_id("Add");
1013        let sub_trt = traits.trait_id("Sub");
1014        let mul_trt = traits.trait_id("Mul");
1015        let div_trt = traits.trait_id("Div");
1016        let rem_trt = traits.trait_id("Rem");
1017        let div_rem_trt = traits.trait_id("DivRem");
1018        let neg_trt = traits.trait_id("Neg");
1019        let arith_module = ops.submodule("arith");
1020        let add_assign_trt = arith_module.trait_id("AddAssign");
1021        let sub_assign_trt = arith_module.trait_id("SubAssign");
1022        let mul_assign_trt = arith_module.trait_id("MulAssign");
1023        let div_assign_trt = arith_module.trait_id("DivAssign");
1024        let rem_assign_trt = arith_module.trait_id("RemAssign");
1025        let bitnot_trt = traits.trait_id("BitNot");
1026        let bitand_trt = traits.trait_id("BitAnd");
1027        let bitor_trt = traits.trait_id("BitOr");
1028        let bitxor_trt = traits.trait_id("BitXor");
1029        let not_trt = traits.trait_id("Not");
1030        let partialeq_trt = traits.trait_id("PartialEq");
1031        let partialord_trt = traits.trait_id("PartialOrd");
1032        let range_module = ops.submodule("range");
1033        let range_op_trt = range_module.trait_id("RangeOp");
1034        let range_inclusive_op_trt = range_module.trait_id("RangeInclusiveOp");
1035        let iter_traits = core.submodule("iter").submodule("traits");
1036        let into_iterator_trt: TraitId<'db> =
1037            iter_traits.submodule("collect").trait_id("IntoIterator");
1038        let iterator_trt = iter_traits.submodule("iterator").trait_id("Iterator");
1039        let fn_module = ops.submodule("function");
1040        let fn_trt = fn_module.trait_id("Fn");
1041        let fn_once_trt = fn_module.trait_id("FnOnce");
1042        let index_module = ops.submodule("index");
1043        let starknet = core.submodule("starknet");
1044        let bounded_int = core.submodule("internal").submodule("bounded_int");
1045        let trait_fn = |trait_id: TraitId<'db>, name: &'static str| {
1046            // TODO(eytan-starkware): Change &str to SmolStrId in trait_fn.
1047            db.trait_function_by_name(trait_id, SmolStrId::from(db, name)).unwrap().unwrap()
1048        };
1049        let tuple_submodule = core.submodule("tuple").id;
1050        let fixed_size_array_submodule = core.submodule("fixed_size_array").id;
1051        Self {
1052            felt252: core.ty("felt252", vec![]),
1053            u8: integer.ty("u8", vec![]),
1054            u16: integer.ty("u16", vec![]),
1055            u32: integer.ty("u32", vec![]),
1056            u64: integer.ty("u64", vec![]),
1057            u128: integer.ty("u128", vec![]),
1058            u256: integer.ty("u256", vec![]),
1059            i8: integer.ty("i8", vec![]),
1060            i16: integer.ty("i16", vec![]),
1061            i32: integer.ty("i32", vec![]),
1062            i64: integer.ty("i64", vec![]),
1063            i128: integer.ty("i128", vec![]),
1064            class_hash: starknet.submodule("class_hash").ty("ClassHash", vec![]),
1065            contract_address: starknet.submodule("contract_address").ty("ContractAddress", vec![]),
1066            numeric_literal_trt: integer.trait_id("NumericLiteral"),
1067            string_literal_trt: core.submodule("string").trait_id("StringLiteral"),
1068            index_trt: index_module.trait_id("Index"),
1069            index_view_trt: index_module.trait_id("IndexView"),
1070            deref_trt,
1071            deref_mut_trt,
1072            copy_trt: traits.trait_id("Copy"),
1073            drop_trt: traits.trait_id("Drop"),
1074            destruct_trt,
1075            panic_destruct_trt,
1076            add_trt,
1077            sub_trt,
1078            mul_trt,
1079            div_trt,
1080            rem_trt,
1081            div_rem_trt,
1082            neg_trt,
1083            add_assign_trt,
1084            sub_assign_trt,
1085            mul_assign_trt,
1086            div_assign_trt,
1087            rem_assign_trt,
1088            bitnot_trt,
1089            bitand_trt,
1090            bitor_trt,
1091            bitxor_trt,
1092            not_trt,
1093            partialeq_trt,
1094            partialord_trt,
1095            range_op_trt,
1096            range_inclusive_op_trt,
1097            into_iterator_trt,
1098            iterator_trt,
1099            fn_trt,
1100            fn_once_trt,
1101            type_eq_trt: core.submodule("metaprogramming").trait_id("TypeEqual"),
1102            felt252_dict_value_trt: traits.trait_id("Felt252DictValue"),
1103            deref_fn: trait_fn(deref_trt, "deref"),
1104            deref_mut_fn: trait_fn(deref_mut_trt, "deref_mut"),
1105            destruct_fn: trait_fn(destruct_trt, "destruct"),
1106            panic_destruct_fn: trait_fn(panic_destruct_trt, "panic_destruct"),
1107            add_fn: trait_fn(add_trt, "add"),
1108            sub_fn: trait_fn(sub_trt, "sub"),
1109            mul_fn: trait_fn(mul_trt, "mul"),
1110            div_fn: trait_fn(div_trt, "div"),
1111            rem_fn: trait_fn(rem_trt, "rem"),
1112            div_rem_fn: trait_fn(div_rem_trt, "div_rem"),
1113            neg_fn: trait_fn(neg_trt, "neg"),
1114            add_assign_fn: trait_fn(add_assign_trt, "add_assign"),
1115            sub_assign_fn: trait_fn(sub_assign_trt, "sub_assign"),
1116            mul_assign_fn: trait_fn(mul_assign_trt, "mul_assign"),
1117            div_assign_fn: trait_fn(div_assign_trt, "div_assign"),
1118            rem_assign_fn: trait_fn(rem_assign_trt, "rem_assign"),
1119            bitnot_fn: trait_fn(bitnot_trt, "bitnot"),
1120            bitand_fn: trait_fn(bitand_trt, "bitand"),
1121            bitor_fn: trait_fn(bitor_trt, "bitor"),
1122            bitxor_fn: trait_fn(bitxor_trt, "bitxor"),
1123            not_fn: trait_fn(not_trt, "not"),
1124            eq_fn: trait_fn(partialeq_trt, "eq"),
1125            ne_fn: trait_fn(partialeq_trt, "ne"),
1126            lt_fn: trait_fn(partialord_trt, "lt"),
1127            gt_fn: trait_fn(partialord_trt, "gt"),
1128            le_fn: trait_fn(partialord_trt, "le"),
1129            ge_fn: trait_fn(partialord_trt, "ge"),
1130            range_fn: trait_fn(range_op_trt, "range"),
1131            range_inclusive_fn: trait_fn(range_inclusive_op_trt, "range_inclusive"),
1132            into_iter_fn: trait_fn(into_iterator_trt, "into_iter"),
1133            next_fn: trait_fn(iterator_trt, "next"),
1134            call_fn: trait_fn(fn_trt, "call"),
1135            call_once_fn: trait_fn(fn_once_trt, "call"),
1136            upcast_fn: bounded_int.generic_function_id("upcast"),
1137            downcast_fn: bounded_int.generic_function_id("downcast"),
1138            tuple_submodule,
1139            fixed_size_array_submodule,
1140        }
1141    }
1142}
1143
1144/// Implementation of [CorelibSemantic::core_info].
1145pub fn core_info(db: &dyn Database) -> Arc<CoreInfo<'_>> {
1146    CoreInfo::new(db).into()
1147}
1148
1149/// Query implementation of [CorelibSemantic::core_info].
1150#[salsa::tracked]
1151pub fn core_info_tracked(db: &dyn Database) -> Arc<CoreInfo<'_>> {
1152    core_info(db)
1153}
1154
1155/// Trait for corelib-related semantic queries.
1156pub trait CorelibSemantic<'db>: Database {
1157    fn core_crate(&'db self) -> CrateId<'db> {
1158        core_crate_tracked(self.as_dyn_database())
1159    }
1160    fn core_module(&'db self) -> ModuleId<'db> {
1161        core_module_tracked(self.as_dyn_database())
1162    }
1163    fn core_info(&'db self) -> Arc<CoreInfo<'db>> {
1164        core_info_tracked(self.as_dyn_database())
1165    }
1166}
1167impl<'db, T: Database + ?Sized> CorelibSemantic<'db> for T {}