1use std::iter::zip;
2use std::sync::Arc;
3
4use cairo_lang_debug::DebugWithDb;
5use cairo_lang_defs::db::DefsGroup;
6use cairo_lang_defs::ids::{
7 ConstantId, ExternFunctionId, GenericParamId, LanguageElementId, LookupItemId, ModuleItemId,
8 NamedLanguageElementId, TopLevelLanguageElementId, TraitConstantId, TraitId, VarId,
9};
10use cairo_lang_diagnostics::{
11 DiagnosticAdded, DiagnosticEntry, DiagnosticNote, Diagnostics, Maybe, MaybeAsRef,
12 skip_diagnostic,
13};
14use cairo_lang_filesystem::ids::SmolStrId;
15use cairo_lang_proc_macros::{DebugWithDb, SemanticObject};
16use cairo_lang_syntax::node::ast::ItemConstant;
17use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
18use cairo_lang_syntax::node::{TypedStablePtr, TypedSyntaxNode};
19use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
20use cairo_lang_utils::unordered_hash_map::UnorderedHashMap;
21use cairo_lang_utils::unordered_hash_set::UnorderedHashSet;
22use cairo_lang_utils::{Intern, define_short_id, extract_matches, require, try_extract_matches};
23use itertools::Itertools;
24use num_bigint::BigInt;
25use num_traits::{Num, ToPrimitive, Zero};
26use salsa::Database;
27
28use super::functions::{GenericFunctionId, GenericFunctionWithBodyId};
29use super::imp::{ImplId, ImplLongId};
30use crate::corelib::{
31 CoreInfo, CorelibSemantic, LiteralError, core_nonzero_ty, false_variant, get_core_ty_by_name,
32 true_variant, try_extract_nz_wrapped_type, unit_ty, validate_literal,
33};
34use crate::diagnostic::{SemanticDiagnosticKind, SemanticDiagnostics, SemanticDiagnosticsBuilder};
35use crate::expr::compute::{ComputationContext, ExprAndId, compute_expr_semantic};
36use crate::expr::inference::conform::InferenceConform;
37use crate::expr::inference::{ConstVar, InferenceId};
38use crate::helper::ModuleHelper;
39use crate::items::enm::SemanticEnumEx;
40use crate::items::extern_function::ExternFunctionSemantic;
41use crate::items::free_function::FreeFunctionSemantic;
42use crate::items::function_with_body::FunctionWithBodySemantic;
43use crate::items::generics::GenericParamSemantic;
44use crate::items::imp::ImplSemantic;
45use crate::items::structure::StructSemantic;
46use crate::items::trt::TraitSemantic;
47use crate::resolve::{Resolver, ResolverData};
48use crate::substitution::{GenericSubstitution, SemanticRewriter};
49use crate::types::resolve_type;
50use crate::{
51 Arenas, ConcreteFunction, ConcreteTypeId, ConcreteVariant, Condition, Expr, ExprBlock,
52 ExprConstant, ExprFunctionCall, ExprFunctionCallArg, ExprId, ExprMemberAccess, ExprStructCtor,
53 FunctionId, GenericParam, LogicalOperator, Pattern, PatternId, SemanticDiagnostic, Statement,
54 TypeId, TypeLongId, semantic_object_for_id,
55};
56
57#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
58#[debug_db(dyn Database)]
59pub struct Constant<'db> {
60 pub value: ExprId,
62 pub arenas: Arc<Arenas<'db>>,
64}
65
66unsafe impl<'db> salsa::Update for Constant<'db> {
68 unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
69 let old_constant: &mut Constant<'db> = unsafe { &mut *old_pointer };
70
71 if old_constant.value != new_value.value {
72 *old_constant = new_value;
73 return true;
74 }
75
76 false
77 }
78}
79
80impl<'db> Constant<'db> {
81 pub fn ty(&self) -> TypeId<'db> {
82 self.arenas.exprs[self.value].ty()
83 }
84}
85
86#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, salsa::Update)]
90#[debug_db(dyn Database)]
91pub struct ConstantData<'db> {
92 pub diagnostics: Diagnostics<'db, SemanticDiagnostic<'db>>,
93 pub constant: Maybe<Constant<'db>>,
94 pub const_value: ConstValueId<'db>,
95 pub resolver_data: Arc<ResolverData<'db>>,
96}
97
98define_short_id!(ConstValueId, ConstValue<'db>);
99semantic_object_for_id!(ConstValueId, ConstValue<'a>);
100impl<'db> ConstValueId<'db> {
101 pub fn format(&self, db: &dyn Database) -> String {
102 format!("{:?}", self.long(db).debug(db))
103 }
104
105 pub fn is_fully_concrete(&self, db: &dyn Database) -> bool {
107 self.long(db).is_fully_concrete(db)
108 }
109
110 pub fn is_var_free(&self, db: &dyn Database) -> bool {
112 self.long(db).is_var_free(db)
113 }
114
115 pub fn ty(&self, db: &'db dyn Database) -> Maybe<TypeId<'db>> {
117 self.long(db).ty(db)
118 }
119}
120
121#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject, salsa::Update)]
123pub enum ConstValue<'db> {
124 Int(#[dont_rewrite] BigInt, TypeId<'db>),
125 Struct(Vec<ConstValueId<'db>>, TypeId<'db>),
126 Enum(ConcreteVariant<'db>, ConstValueId<'db>),
127 NonZero(ConstValueId<'db>),
128 Generic(#[dont_rewrite] GenericParamId<'db>),
129 ImplConstant(ImplConstantId<'db>),
130 Var(ConstVar<'db>, TypeId<'db>),
131 Missing(#[dont_rewrite] DiagnosticAdded),
133}
134impl<'db> ConstValue<'db> {
135 pub fn is_fully_concrete(&self, db: &dyn Database) -> bool {
137 self.ty(db).unwrap().is_fully_concrete(db)
138 && match self {
139 ConstValue::Int(_, _) => true,
140 ConstValue::Struct(members, _) => {
141 members.iter().all(|member| member.is_fully_concrete(db))
142 }
143 ConstValue::Enum(_, val) | ConstValue::NonZero(val) => val.is_fully_concrete(db),
144 ConstValue::Generic(_)
145 | ConstValue::Var(_, _)
146 | ConstValue::Missing(_)
147 | ConstValue::ImplConstant(_) => false,
148 }
149 }
150
151 pub fn is_var_free(&self, db: &dyn Database) -> bool {
153 self.ty(db).unwrap().is_var_free(db)
154 && match self {
155 ConstValue::Int(_, _) | ConstValue::Generic(_) | ConstValue::Missing(_) => true,
156 ConstValue::Struct(members, _) => {
157 members.iter().all(|member| member.is_var_free(db))
158 }
159 ConstValue::Enum(_, val) | ConstValue::NonZero(val) => val.is_var_free(db),
160 ConstValue::Var(_, _) => false,
161 ConstValue::ImplConstant(impl_constant) => impl_constant.impl_id().is_var_free(db),
162 }
163 }
164
165 pub fn ty(&self, db: &'db dyn Database) -> Maybe<TypeId<'db>> {
167 Ok(match self {
168 ConstValue::Int(_, ty) => *ty,
169 ConstValue::Struct(_, ty) => *ty,
170 ConstValue::Enum(variant, _) => {
171 TypeLongId::Concrete(ConcreteTypeId::Enum(variant.concrete_enum_id)).intern(db)
172 }
173 ConstValue::NonZero(value) => core_nonzero_ty(db, value.ty(db)?),
174 ConstValue::Generic(param) => {
175 extract_matches!(db.generic_param_semantic(*param)?, GenericParam::Const).ty
176 }
177 ConstValue::Var(_, ty) => *ty,
178 ConstValue::Missing(_) => TypeId::missing(db, skip_diagnostic()),
179 ConstValue::ImplConstant(impl_constant_id) => {
180 db.impl_constant_concrete_implized_type(*impl_constant_id)?
181 }
182 })
183 }
184
185 pub fn to_int(&self) -> Option<&BigInt> {
187 match self {
188 ConstValue::Int(value, _) => Some(value),
189 _ => None,
190 }
191 }
192}
193
194#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, SemanticObject, salsa::Update)]
196pub struct ImplConstantId<'db> {
197 impl_id: ImplId<'db>,
199 trait_constant_id: TraitConstantId<'db>,
201}
202
203impl<'db> ImplConstantId<'db> {
204 pub fn new(
207 impl_id: ImplId<'db>,
208 trait_constant_id: TraitConstantId<'db>,
209 db: &dyn Database,
210 ) -> Self {
211 if let ImplLongId::Concrete(concrete_impl) = impl_id.long(db) {
212 let impl_def_id = concrete_impl.impl_def_id(db);
213 assert_eq!(Ok(trait_constant_id.trait_id(db)), db.impl_def_trait(impl_def_id));
214 }
215
216 ImplConstantId { impl_id, trait_constant_id }
217 }
218 pub fn impl_id(&self) -> ImplId<'db> {
219 self.impl_id
220 }
221 pub fn trait_constant_id(&self) -> TraitConstantId<'db> {
222 self.trait_constant_id
223 }
224
225 pub fn format(&self, db: &dyn Database) -> String {
226 format!("{}::{}", self.impl_id.name(db), self.trait_constant_id.name(db).long(db))
227 }
228}
229impl<'db> DebugWithDb<'db> for ImplConstantId<'db> {
230 type Db = dyn Database;
231
232 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
233 write!(f, "{}", self.format(db))
234 }
235}
236
237#[salsa::tracked(returns(ref), cycle_result=constant_semantic_data_cycle)]
239fn constant_semantic_data<'db>(
240 db: &'db dyn Database,
241 const_id: ConstantId<'db>,
242 in_cycle: bool,
243) -> Maybe<ConstantData<'db>> {
244 let lookup_item_id = LookupItemId::ModuleItem(ModuleItemId::Constant(const_id));
245 if in_cycle {
246 constant_semantic_data_cycle_helper(
247 db,
248 &db.module_constant_by_id(const_id)?,
249 lookup_item_id,
250 None,
251 &const_id,
252 )
253 } else {
254 constant_semantic_data_helper(
255 db,
256 &db.module_constant_by_id(const_id)?,
257 lookup_item_id,
258 None,
259 &const_id,
260 )
261 }
262}
263
264fn constant_semantic_data_cycle<'db>(
266 db: &'db dyn Database,
267 const_id: ConstantId<'db>,
268 _in_cycle: bool,
269) -> Maybe<ConstantData<'db>> {
270 let lookup_item_id = LookupItemId::ModuleItem(ModuleItemId::Constant(const_id));
271 constant_semantic_data_cycle_helper(
272 db,
273 &db.module_constant_by_id(const_id)?,
274 lookup_item_id,
275 None,
276 &const_id,
277 )
278}
279
280pub fn constant_semantic_data_helper<'db>(
282 db: &'db dyn Database,
283 constant_ast: &ItemConstant<'db>,
284 lookup_item_id: LookupItemId<'db>,
285 parent_resolver_data: Option<Arc<ResolverData<'db>>>,
286 element_id: &impl LanguageElementId<'db>,
287) -> Maybe<ConstantData<'db>> {
288 let mut diagnostics: SemanticDiagnostics<'_> = SemanticDiagnostics::default();
289 let inference_id = InferenceId::LookupItemDeclaration(lookup_item_id);
294
295 let mut resolver = match parent_resolver_data {
296 Some(parent_resolver_data) => {
297 Resolver::with_data(db, parent_resolver_data.clone_with_inference_id(db, inference_id))
298 }
299 None => Resolver::new(db, element_id.module_id(db), inference_id),
300 };
301 resolver.set_feature_config(element_id, constant_ast, &mut diagnostics);
302
303 let constant_type =
304 resolve_type(db, &mut diagnostics, &mut resolver, &constant_ast.type_clause(db).ty(db));
305
306 let mut ctx = ComputationContext::new_global(db, &mut diagnostics, &mut resolver);
307
308 let value = compute_expr_semantic(&mut ctx, &constant_ast.value(db));
309 let const_value = resolve_const_expr_and_evaluate(
310 db,
311 &mut ctx,
312 &value,
313 constant_ast.stable_ptr(db).untyped(),
314 constant_type,
315 true,
316 );
317 let constant = Ok(Constant { value: value.id, arenas: Arc::new(ctx.arenas) });
318 let const_value = resolver
319 .inference()
320 .rewrite(const_value)
321 .unwrap_or_else(|_| ConstValue::Missing(skip_diagnostic()).intern(db));
322 let resolver_data = Arc::new(resolver.data);
323 Ok(ConstantData { diagnostics: diagnostics.build(), const_value, constant, resolver_data })
324}
325
326pub fn constant_semantic_data_cycle_helper<'db>(
328 db: &'db dyn Database,
329 constant_ast: &ItemConstant<'db>,
330 lookup_item_id: LookupItemId<'db>,
331 parent_resolver_data: Option<Arc<ResolverData<'db>>>,
332 element_id: &impl LanguageElementId<'db>,
333) -> Maybe<ConstantData<'db>> {
334 let mut diagnostics: SemanticDiagnostics<'_> = SemanticDiagnostics::default();
335
336 let inference_id = InferenceId::LookupItemDeclaration(lookup_item_id);
337
338 let resolver = match parent_resolver_data {
339 Some(parent_resolver_data) => {
340 Resolver::with_data(db, parent_resolver_data.clone_with_inference_id(db, inference_id))
341 }
342 None => Resolver::new(db, element_id.module_id(db), inference_id),
343 };
344
345 let resolver_data = Arc::new(resolver.data);
346
347 let diagnostic_added =
348 diagnostics.report(constant_ast.stable_ptr(db), SemanticDiagnosticKind::ConstCycle);
349 Ok(ConstantData {
350 constant: Err(diagnostic_added),
351 const_value: ConstValue::Missing(diagnostic_added).intern(db),
352 diagnostics: diagnostics.build(),
353 resolver_data,
354 })
355}
356
357pub fn validate_const_expr<'db>(ctx: &mut ComputationContext<'db, '_>, expr_id: ExprId) {
359 let info = ctx.db.const_calc_info();
360 let mut eval_ctx = ConstantEvaluateContext {
361 db: ctx.db,
362 info: info.as_ref(),
363 arenas: &ctx.arenas,
364 vars: Default::default(),
365 generic_substitution: Default::default(),
366 depth: 0,
367 diagnostics: ctx.diagnostics,
368 };
369 eval_ctx.validate(expr_id);
370}
371
372pub fn resolve_const_expr_and_evaluate<'db, 'mt>(
374 db: &'db dyn Database,
375 ctx: &'mt mut ComputationContext<'db, '_>,
376 value: &ExprAndId<'db>,
377 const_stable_ptr: SyntaxStablePtrId<'db>,
378 target_type: TypeId<'db>,
379 finalize: bool,
380) -> ConstValueId<'db> {
381 let prev_err_count = ctx.diagnostics.error_count;
382 let mut_ref = &mut ctx.resolver;
383 let mut inference: crate::expr::inference::Inference<'db, '_> = mut_ref.inference();
384 if let Err(err_set) = inference.conform_ty(value.ty(), target_type) {
385 inference.report_on_pending_error(err_set, ctx.diagnostics, const_stable_ptr);
386 }
387
388 if finalize {
389 inference.finalize(ctx.diagnostics, const_stable_ptr);
391 } else if let Err(err_set) = inference.solve() {
392 inference.report_on_pending_error(err_set, ctx.diagnostics, const_stable_ptr);
393 }
394
395 ctx.apply_inference_rewriter_to_exprs();
398
399 match &value.expr {
400 Expr::Constant(ExprConstant { const_value_id, .. }) => *const_value_id,
401 _ if ctx.diagnostics.error_count > prev_err_count => {
403 ConstValue::Missing(skip_diagnostic()).intern(db)
404 }
405 _ => {
406 let info = db.const_calc_info();
407 let mut eval_ctx = ConstantEvaluateContext {
408 db,
409 info: info.as_ref(),
410 arenas: &ctx.arenas,
411 vars: Default::default(),
412 generic_substitution: Default::default(),
413 depth: 0,
414 diagnostics: ctx.diagnostics,
415 };
416 eval_ctx.validate(value.id);
417 if eval_ctx.diagnostics.error_count > prev_err_count {
418 ConstValue::Missing(skip_diagnostic()).intern(db)
419 } else {
420 eval_ctx.evaluate(value.id)
421 }
422 }
423 }
424}
425
426pub fn value_as_const_value<'db>(
428 db: &'db dyn Database,
429 ty: TypeId<'db>,
430 value: &BigInt,
431) -> Result<ConstValueId<'db>, LiteralError<'db>> {
432 validate_literal(db, ty, value)?;
433 let get_basic_const_value = |ty| {
434 let u256_ty = get_core_ty_by_name(db, SmolStrId::from(db, "u256"), vec![]);
435
436 if ty != u256_ty {
437 ConstValue::Int(value.clone(), ty).intern(db)
438 } else {
439 let u128_ty = get_core_ty_by_name(db, SmolStrId::from(db, "u128"), vec![]);
440 let mask128 = BigInt::from(u128::MAX);
441 let low = value & mask128;
442 let high = value >> 128;
443 ConstValue::Struct(
444 vec![
445 (ConstValue::Int(low, u128_ty).intern(db)),
446 (ConstValue::Int(high, u128_ty).intern(db)),
447 ],
448 ty,
449 )
450 .intern(db)
451 }
452 };
453
454 if let Some(inner) = try_extract_nz_wrapped_type(db, ty) {
455 Ok(ConstValue::NonZero(get_basic_const_value(inner)).intern(db))
456 } else {
457 Ok(get_basic_const_value(ty))
458 }
459}
460
461struct ConstantEvaluateContext<'a, 'r, 'mt> {
463 db: &'a dyn Database,
464 info: &'r ConstCalcInfo<'a>,
465 arenas: &'r Arenas<'a>,
466 vars: OrderedHashMap<VarId<'a>, ConstValueId<'a>>,
467 generic_substitution: GenericSubstitution<'a>,
468 depth: usize,
469 diagnostics: &'mt mut SemanticDiagnostics<'a>,
470}
471impl<'a, 'r, 'mt> ConstantEvaluateContext<'a, 'r, 'mt> {
472 fn validate(&mut self, expr_id: ExprId) {
474 match &self.arenas.exprs[expr_id] {
475 Expr::Var(_) | Expr::Constant(_) | Expr::Missing(_) => {}
476 Expr::Block(ExprBlock { statements, tail: Some(inner), .. }) => {
477 for statement_id in statements {
478 match &self.arenas.statements[*statement_id] {
479 Statement::Let(statement) => {
480 self.validate(statement.expr);
481 }
482 Statement::Expr(expr) => {
483 self.validate(expr.expr);
484 }
485 other => {
486 self.diagnostics.report(
487 other.stable_ptr(),
488 SemanticDiagnosticKind::UnsupportedConstant,
489 );
490 }
491 }
492 }
493 self.validate(*inner);
494 }
495 Expr::FunctionCall(expr) => {
496 for arg in &expr.args {
497 match arg {
498 ExprFunctionCallArg::Value(arg) => self.validate(*arg),
499 ExprFunctionCallArg::Reference(var) => {
500 self.diagnostics.report(
501 var.stable_ptr(),
502 SemanticDiagnosticKind::UnsupportedConstant,
503 );
504 }
505 }
506 if let ExprFunctionCallArg::Value(arg) = arg {
507 self.validate(*arg);
508 }
509 }
510 if !self.is_function_const(expr.function) {
511 self.diagnostics.report(
512 expr.stable_ptr.untyped(),
513 SemanticDiagnosticKind::UnsupportedConstant,
514 );
515 }
516 }
517 Expr::Literal(expr) => {
518 if let Err(err) = validate_literal(self.db, expr.ty, &expr.value) {
519 self.diagnostics.report(
520 expr.stable_ptr.untyped(),
521 SemanticDiagnosticKind::LiteralError(err),
522 );
523 }
524 }
525 Expr::Tuple(expr) => {
526 for item in &expr.items {
527 self.validate(*item);
528 }
529 }
530 Expr::StructCtor(ExprStructCtor { members, base_struct: None, .. }) => {
531 for (expr_id, _) in members {
532 self.validate(*expr_id);
533 }
534 }
535 Expr::EnumVariantCtor(expr) => self.validate(expr.value_expr),
536 Expr::MemberAccess(expr) => self.validate(expr.expr),
537 Expr::FixedSizeArray(expr) => match &expr.items {
538 crate::FixedSizeArrayItems::Items(items) => {
539 for item in items {
540 self.validate(*item);
541 }
542 }
543 crate::FixedSizeArrayItems::ValueAndSize(value, _) => {
544 self.validate(*value);
545 }
546 },
547 Expr::Snapshot(expr) => self.validate(expr.inner),
548 Expr::Desnap(expr) => self.validate(expr.inner),
549 Expr::LogicalOperator(expr) => {
550 self.validate(expr.lhs);
551 self.validate(expr.rhs);
552 }
553 Expr::Match(expr) => {
554 self.validate(expr.matched_expr);
555 for arm in &expr.arms {
556 self.validate(arm.expression);
557 }
558 }
559 Expr::If(expr) => {
560 for condition in &expr.conditions {
561 self.validate(match condition {
562 Condition::BoolExpr(id) | Condition::Let(id, _) => *id,
563 });
564 }
565 self.validate(expr.if_block);
566 if let Some(else_block) = expr.else_block {
567 self.validate(else_block);
568 }
569 }
570 other => {
571 self.diagnostics.report(
572 other.stable_ptr().untyped(),
573 SemanticDiagnosticKind::UnsupportedConstant,
574 );
575 }
576 }
577 }
578
579 fn is_function_const(&self, function_id: FunctionId<'a>) -> bool {
581 if function_id == self.panic_with_felt252 {
582 return true;
583 }
584 let db = self.db;
585 let concrete_function = function_id.get_concrete(db);
586 let signature = (|| match concrete_function.generic_function {
587 GenericFunctionId::Free(id) => db.free_function_signature(id),
588 GenericFunctionId::Extern(id) => db.extern_function_signature(id),
589 GenericFunctionId::Impl(id) => {
590 if let ImplLongId::Concrete(impl_id) = id.impl_id.long(db)
591 && let Ok(Some(impl_function_id)) = impl_id.get_impl_function(db, id.function)
592 {
593 return self.db.impl_function_signature(impl_function_id);
594 }
595 self.db.trait_function_signature(id.function)
596 }
597 })();
598 if signature.map(|s| s.is_const) == Ok(true) {
599 return true;
600 }
601 let Ok(Some(body)) = concrete_function.body(db) else { return false };
602 let GenericFunctionWithBodyId::Impl(imp) = body.generic_function(db) else {
603 return false;
604 };
605 let impl_def = imp.concrete_impl_id.impl_def_id(db);
606 if impl_def.parent_module(db).owning_crate(db) != db.core_crate() {
607 return false;
608 }
609 let Ok(trait_id) = db.impl_def_trait(impl_def) else {
610 return false;
611 };
612 self.const_traits.contains(&trait_id)
613 }
614
615 fn evaluate<'ctx>(&'ctx mut self, expr_id: ExprId) -> ConstValueId<'a> {
617 let expr = &self.arenas.exprs[expr_id];
618 let db = self.db;
619 let to_missing = |diag_added| ConstValue::Missing(diag_added).intern(db);
620 match expr {
621 Expr::Var(expr) => self.vars.get(&expr.var).copied().unwrap_or_else(|| {
622 to_missing(
623 self.diagnostics
624 .report(expr.stable_ptr, SemanticDiagnosticKind::UnsupportedConstant),
625 )
626 }),
627 Expr::Constant(expr) => self
628 .generic_substitution
629 .substitute(self.db, expr.const_value_id)
630 .unwrap_or_else(to_missing),
631 Expr::Block(ExprBlock { statements, tail: Some(inner), .. }) => {
632 for statement_id in statements {
633 match &self.arenas.statements[*statement_id] {
634 Statement::Let(statement) => {
635 let value = self.evaluate(statement.expr);
636 self.destructure_pattern(statement.pattern, value);
637 }
638 Statement::Expr(expr) => {
639 self.evaluate(expr.expr);
640 }
641 other => {
642 self.diagnostics.report(
643 other.stable_ptr(),
644 SemanticDiagnosticKind::UnsupportedConstant,
645 );
646 }
647 }
648 }
649 self.evaluate(*inner)
650 }
651 Expr::FunctionCall(expr) => self.evaluate_function_call(expr),
652 Expr::Literal(expr) => value_as_const_value(db, expr.ty, &expr.value)
653 .expect("LiteralError should have been caught on `validate`"),
654 Expr::Tuple(expr) => ConstValue::Struct(
655 expr.items.iter().map(|expr_id| self.evaluate(*expr_id)).collect(),
656 expr.ty,
657 )
658 .intern(db),
659 Expr::StructCtor(ExprStructCtor {
660 members,
661 base_struct: None,
662 ty,
663 concrete_struct_id,
664 ..
665 }) => {
666 let member_order = match db.concrete_struct_members(*concrete_struct_id) {
667 Ok(member_order) => member_order,
668 Err(diag_add) => return to_missing(diag_add),
669 };
670 ConstValue::Struct(
671 member_order
672 .values()
673 .map(|m| {
674 members
675 .iter()
676 .find(|(_, member_id)| m.id == *member_id)
677 .map(|(expr_id, _)| self.evaluate(*expr_id))
678 .expect("Should have been caught by semantic validation")
679 })
680 .collect(),
681 *ty,
682 )
683 .intern(db)
684 }
685 Expr::EnumVariantCtor(expr) => {
686 ConstValue::Enum(expr.variant, self.evaluate(expr.value_expr)).intern(db)
687 }
688 Expr::MemberAccess(expr) => {
689 self.evaluate_member_access(expr).unwrap_or_else(to_missing)
690 }
691 Expr::FixedSizeArray(expr) => ConstValue::Struct(
692 match &expr.items {
693 crate::FixedSizeArrayItems::Items(items) => {
694 items.iter().map(|expr_id| self.evaluate(*expr_id)).collect()
695 }
696 crate::FixedSizeArrayItems::ValueAndSize(value, count) => {
697 let value = self.evaluate(*value);
698 if let Some(count) = count.long(db).to_int() {
699 vec![value; count.to_usize().unwrap()]
700 } else {
701 self.diagnostics.report(
702 expr.stable_ptr.untyped(),
703 SemanticDiagnosticKind::UnsupportedConstant,
704 );
705 vec![]
706 }
707 }
708 },
709 expr.ty,
710 )
711 .intern(db),
712 Expr::Snapshot(expr) => self.evaluate(expr.inner),
713 Expr::Desnap(expr) => self.evaluate(expr.inner),
714 Expr::LogicalOperator(expr) => {
715 let lhs = self.evaluate(expr.lhs);
716 if let ConstValue::Enum(v, _) = lhs.long(db) {
717 let early_return_variant = match expr.op {
718 LogicalOperator::AndAnd => false_variant(self.db),
719 LogicalOperator::OrOr => true_variant(self.db),
720 };
721 if *v == early_return_variant { lhs } else { self.evaluate(expr.lhs) }
722 } else {
723 to_missing(skip_diagnostic())
724 }
725 }
726 Expr::Match(expr) => {
727 let value = self.evaluate(expr.matched_expr);
728 let ConstValue::Enum(variant, value) = value.long(db) else {
729 return to_missing(skip_diagnostic());
730 };
731 for arm in &expr.arms {
732 for pattern_id in &arm.patterns {
733 let pattern = &self.arenas.patterns[*pattern_id];
734 if matches!(pattern, Pattern::Otherwise(_)) {
735 return self.evaluate(arm.expression);
736 }
737 let Pattern::EnumVariant(pattern) = pattern else {
738 continue;
739 };
740 if pattern.variant.idx != variant.idx {
741 continue;
742 }
743 if let Some(inner_pattern) = pattern.inner_pattern {
744 self.destructure_pattern(inner_pattern, *value);
745 }
746 return self.evaluate(arm.expression);
747 }
748 }
749 to_missing(
750 self.diagnostics.report(
751 expr.stable_ptr.untyped(),
752 SemanticDiagnosticKind::UnsupportedConstant,
753 ),
754 )
755 }
756 Expr::If(expr) => {
757 let mut if_condition: bool = true;
758 for condition in &expr.conditions {
759 match condition {
760 crate::Condition::BoolExpr(id) => {
761 let condition = self.evaluate(*id);
762 let ConstValue::Enum(variant, _) = condition.long(db) else {
763 return to_missing(skip_diagnostic());
764 };
765 if *variant != true_variant(self.db) {
766 if_condition = false;
767 break;
768 }
769 }
770 crate::Condition::Let(id, patterns) => {
771 let value = self.evaluate(*id);
772 let ConstValue::Enum(variant, value) = value.long(db) else {
773 return to_missing(skip_diagnostic());
774 };
775 let mut found_pattern = false;
776 for pattern_id in patterns {
777 let Pattern::EnumVariant(pattern) =
778 &self.arenas.patterns[*pattern_id]
779 else {
780 continue;
781 };
782 if pattern.variant != *variant {
783 continue;
785 }
786 if let Some(inner_pattern) = pattern.inner_pattern {
787 self.destructure_pattern(inner_pattern, *value);
788 }
789 found_pattern = true;
790 break;
791 }
792 if !found_pattern {
793 if_condition = false;
794 break;
795 }
796 }
797 }
798 }
799
800 if if_condition {
801 self.evaluate(expr.if_block)
802 } else if let Some(else_block) = expr.else_block {
803 self.evaluate(else_block)
804 } else {
805 self.unit_const
806 }
807 }
808 _ => to_missing(skip_diagnostic()),
809 }
810 }
811
812 fn evaluate_function_call(&mut self, expr: &ExprFunctionCall<'a>) -> ConstValueId<'a> {
814 let db = self.db;
815 let to_missing = |diag_added| ConstValue::Missing(diag_added).intern(db);
816 let args = expr
817 .args
818 .iter()
819 .filter_map(|arg| try_extract_matches!(arg, ExprFunctionCallArg::Value))
820 .map(|arg| self.evaluate(*arg))
821 .collect_vec();
822 if expr.function == self.panic_with_felt252 {
823 return to_missing(self.diagnostics.report(
824 expr.stable_ptr.untyped(),
825 SemanticDiagnosticKind::FailedConstantCalculation,
826 ));
827 }
828 let concrete_function =
829 match self.generic_substitution.substitute(db, expr.function.get_concrete(db)) {
830 Ok(v) => v,
831 Err(err) => return to_missing(err),
832 };
833 if let Some(calc_result) =
834 self.evaluate_const_function_call(&concrete_function, &args, expr)
835 {
836 return calc_result;
837 }
838
839 let imp = extract_matches!(concrete_function.generic_function, GenericFunctionId::Impl);
840 let bool_value = |condition: bool| {
841 if condition { self.true_const } else { self.false_const }
842 };
843
844 if imp.function == self.eq_fn {
845 return bool_value(args[0] == args[1]);
846 } else if imp.function == self.ne_fn {
847 return bool_value(args[0] != args[1]);
848 } else if imp.function == self.not_fn {
849 return bool_value(args[0] == self.false_const);
850 }
851
852 let args = match args
853 .into_iter()
854 .map(|arg| NumericArg::try_new(db, arg))
855 .collect::<Option<Vec<_>>>()
856 {
857 Some(args) => args,
858 None => return to_missing(skip_diagnostic()),
861 };
862 let mut value = match imp.function {
863 id if id == self.neg_fn => -&args[0].v,
864 id if id == self.add_fn => &args[0].v + &args[1].v,
865 id if id == self.sub_fn => &args[0].v - &args[1].v,
866 id if id == self.mul_fn => &args[0].v * &args[1].v,
867 id if (id == self.div_fn || id == self.rem_fn) && args[1].v.is_zero() => {
868 return to_missing(
869 self.diagnostics
870 .report(expr.stable_ptr.untyped(), SemanticDiagnosticKind::DivisionByZero),
871 );
872 }
873 id if id == self.div_fn => &args[0].v / &args[1].v,
874 id if id == self.rem_fn => &args[0].v % &args[1].v,
875 id if id == self.bitand_fn => &args[0].v & &args[1].v,
876 id if id == self.bitor_fn => &args[0].v | &args[1].v,
877 id if id == self.bitxor_fn => &args[0].v ^ &args[1].v,
878 id if id == self.lt_fn => return bool_value(args[0].v < args[1].v),
879 id if id == self.le_fn => return bool_value(args[0].v <= args[1].v),
880 id if id == self.gt_fn => return bool_value(args[0].v > args[1].v),
881 id if id == self.ge_fn => return bool_value(args[0].v >= args[1].v),
882 id if id == self.div_rem_fn => {
883 return ConstValue::Struct(
886 vec![
887 value_as_const_value(db, args[0].ty, &(&args[0].v / &args[1].v)).unwrap(),
888 value_as_const_value(db, args[0].ty, &(&args[0].v % &args[1].v)).unwrap(),
889 ],
890 expr.ty,
891 )
892 .intern(db);
893 }
894 _ => {
895 unreachable!("Unexpected function call in constant lowering: {:?}", expr)
896 }
897 };
898 if expr.ty == db.core_info().felt252 {
899 value %= BigInt::from_str_radix(
901 "800000000000011000000000000000000000000000000000000000000000001",
902 16,
903 )
904 .unwrap();
905 }
906 value_as_const_value(db, expr.ty, &value)
907 .map_err(|err| {
908 self.diagnostics
909 .report(expr.stable_ptr.untyped(), SemanticDiagnosticKind::LiteralError(err))
910 })
911 .unwrap_or_else(to_missing)
912 }
913
914 fn evaluate_const_function_call(
916 &mut self,
917 concrete_function: &ConcreteFunction<'a>,
918 args: &[ConstValueId<'a>],
919 expr: &ExprFunctionCall<'a>,
920 ) -> Option<ConstValueId<'a>> {
921 let db = self.db;
922 if let GenericFunctionId::Extern(extern_fn) = concrete_function.generic_function {
923 let expr_ty = self.generic_substitution.substitute(db, expr.ty).ok()?;
924 if self.upcast_fns.contains(&extern_fn) {
925 let [arg] = args else { return None };
926 return Some(ConstValue::Int(arg.long(db).to_int()?.clone(), expr_ty).intern(db));
927 } else if self.unwrap_non_zero == extern_fn {
928 let [arg] = args else { return None };
929 return try_extract_matches!(arg.long(db), ConstValue::NonZero).copied();
930 } else if let Some(reversed) = self.downcast_fns.get(&extern_fn) {
931 let [arg] = args else { return None };
932 let value = arg.long(db).to_int()?;
933 let TypeLongId::Concrete(ConcreteTypeId::Enum(enm)) = expr_ty.long(db) else {
934 return None;
935 };
936 let (variant0, variant1) =
937 db.concrete_enum_variants(*enm).ok()?.into_iter().collect_tuple()?;
938 let (some, none) =
939 if *reversed { (variant1, variant0) } else { (variant0, variant1) };
940 let success_ty = some.ty;
941 return Some(match validate_literal(db, success_ty, value) {
942 Ok(()) => ConstValue::Enum(
943 some,
944 ConstValue::Int(value.clone(), success_ty).intern(db),
945 )
946 .intern(db),
947 Err(LiteralError::OutOfRange(_)) => {
948 ConstValue::Enum(none, self.unit_const).intern(db)
949 }
950 Err(LiteralError::InvalidTypeForLiteral(_)) => unreachable!(
951 "`downcast` is only allowed into types that can be literals. Got `{}`.",
952 success_ty.format(db)
953 ),
954 });
955 } else if self.nz_fns.contains(&extern_fn) {
956 let [arg] = args else { return None };
957 let (ty, is_zero) = match arg.long(db) {
958 ConstValue::Int(val, ty) => (ty, val.is_zero()),
959 ConstValue::Struct(members, ty) => (
960 ty,
961 members.iter().all(|member| match member.long(db) {
963 ConstValue::Int(val, _) => val.is_zero(),
964 _ => false,
965 }),
966 ),
967 _ => unreachable!(
968 "`is_zero` is only allowed for integers got `{}`",
969 arg.ty(db).unwrap().format(db)
970 ),
971 };
972
973 return Some(
974 if is_zero {
975 ConstValue::Enum(
976 crate::corelib::jump_nz_zero_variant(db, *ty),
977 self.unit_const,
978 )
979 } else {
980 ConstValue::Enum(
981 crate::corelib::jump_nz_nonzero_variant(db, *ty),
982 ConstValue::NonZero(*arg).intern(db),
983 )
984 }
985 .intern(db),
986 );
987 } else {
988 unreachable!(
989 "Unexpected extern function in constant lowering: `{}`",
990 extern_fn.full_path(db)
991 );
992 }
993 }
994 let body_id = concrete_function.body(db).ok()??;
995 let concrete_body_id = body_id.function_with_body_id(db);
996 let signature = db.function_with_body_signature(concrete_body_id).ok()?;
997 require(signature.is_const)?;
998 let generic_substitution = body_id.substitution(db).ok()?;
999 let body = db.function_body(concrete_body_id).ok()?;
1000 const MAX_CONST_EVAL_DEPTH: usize = 100;
1001 if self.depth > MAX_CONST_EVAL_DEPTH {
1002 return Some(
1003 ConstValue::Missing(self.diagnostics.report(
1004 expr.stable_ptr,
1005 SemanticDiagnosticKind::ConstantCalculationDepthExceeded,
1006 ))
1007 .intern(db),
1008 );
1009 }
1010 let mut diagnostics = SemanticDiagnostics::default();
1011 let mut inner = ConstantEvaluateContext {
1012 db,
1013 info: self.info,
1014 arenas: &body.arenas,
1015 vars: signature
1016 .params
1017 .iter()
1018 .map(|p| VarId::Param(p.id))
1019 .zip(args.iter().cloned())
1020 .collect(),
1021 generic_substitution,
1022 depth: self.depth + 1,
1023 diagnostics: &mut diagnostics,
1024 };
1025 let value = inner.evaluate(body.body_expr);
1026 for diagnostic in diagnostics.build().get_all() {
1027 let location = diagnostic.location(db);
1028 let (inner_diag, mut notes) = match diagnostic.kind {
1029 SemanticDiagnosticKind::ConstantCalculationDepthExceeded => {
1030 self.diagnostics.report(
1031 expr.stable_ptr,
1032 SemanticDiagnosticKind::ConstantCalculationDepthExceeded,
1033 );
1034 continue;
1035 }
1036 SemanticDiagnosticKind::InnerFailedConstantCalculation(inner_diag, notes) => {
1037 (inner_diag, notes)
1038 }
1039 _ => (diagnostic.into(), vec![]),
1040 };
1041 notes.push(DiagnosticNote::with_location(
1042 format!("In `{}`", concrete_function.full_path(db)),
1043 location,
1044 ));
1045 self.diagnostics.report(
1046 expr.stable_ptr,
1047 SemanticDiagnosticKind::InnerFailedConstantCalculation(inner_diag, notes),
1048 );
1049 }
1050 Some(value)
1051 }
1052
1053 fn evaluate_member_access(&mut self, expr: &ExprMemberAccess<'a>) -> Maybe<ConstValueId<'a>> {
1055 let full_struct = self.evaluate(expr.expr);
1056 let ConstValue::Struct(values, _) = full_struct.long(self.db) else {
1057 return Err(skip_diagnostic());
1059 };
1060 let members = self.db.concrete_struct_members(expr.concrete_struct_id)?;
1061 let Some(member_idx) = members.iter().position(|(_, member)| member.id == expr.member)
1062 else {
1063 return Err(skip_diagnostic());
1065 };
1066 Ok(values[member_idx])
1067 }
1068
1069 fn destructure_pattern(&mut self, pattern_id: PatternId, value: ConstValueId<'a>) {
1071 let pattern = &self.arenas.patterns[pattern_id];
1072 let db = self.db;
1073 match pattern {
1074 Pattern::Literal(_)
1075 | Pattern::StringLiteral(_)
1076 | Pattern::Otherwise(_)
1077 | Pattern::Missing(_) => {}
1078 Pattern::Variable(pattern) => {
1079 self.vars.insert(VarId::Local(pattern.var.id), value);
1080 }
1081 Pattern::Struct(pattern) => {
1082 if let ConstValue::Struct(inner_values, _) = value.long(db) {
1083 let member_order = match db.concrete_struct_members(pattern.concrete_struct_id)
1084 {
1085 Ok(member_order) => member_order,
1086 Err(_) => return,
1087 };
1088 for (member, inner_value) in zip(member_order.values(), inner_values) {
1089 if let Some((inner_pattern, _)) =
1090 pattern.field_patterns.iter().find(|(_, field)| member.id == field.id)
1091 {
1092 self.destructure_pattern(*inner_pattern, *inner_value);
1093 }
1094 }
1095 }
1096 }
1097 Pattern::Tuple(pattern) => {
1098 if let ConstValue::Struct(inner_values, _) = value.long(db) {
1099 for (inner_pattern, inner_value) in zip(&pattern.field_patterns, inner_values) {
1100 self.destructure_pattern(*inner_pattern, *inner_value);
1101 }
1102 }
1103 }
1104 Pattern::FixedSizeArray(pattern) => {
1105 if let ConstValue::Struct(inner_values, _) = value.long(db) {
1106 for (inner_pattern, inner_value) in
1107 zip(&pattern.elements_patterns, inner_values)
1108 {
1109 self.destructure_pattern(*inner_pattern, *inner_value);
1110 }
1111 }
1112 }
1113 Pattern::EnumVariant(pattern) => {
1114 if let ConstValue::Enum(variant, inner_value) = value.long(db)
1115 && pattern.variant == *variant
1116 && let Some(inner_pattern) = pattern.inner_pattern
1117 {
1118 self.destructure_pattern(inner_pattern, *inner_value);
1119 }
1120 }
1121 }
1122 }
1123}
1124
1125impl<'db, 'r> std::ops::Deref for ConstantEvaluateContext<'db, 'r, '_> {
1126 type Target = ConstCalcInfo<'db>;
1127 fn deref(&self) -> &Self::Target {
1128 self.info
1129 }
1130}
1131
1132struct NumericArg<'db> {
1134 v: BigInt,
1136 ty: TypeId<'db>,
1138}
1139impl<'db> NumericArg<'db> {
1140 fn try_new(db: &'db dyn Database, arg: ConstValueId<'db>) -> Option<Self> {
1141 Some(Self { ty: arg.ty(db).ok()?, v: numeric_arg_value(db, arg)? })
1142 }
1143}
1144
1145fn numeric_arg_value<'db>(db: &'db dyn Database, value: ConstValueId<'db>) -> Option<BigInt> {
1148 match value.long(db) {
1149 ConstValue::Int(value, _) => Some(value.clone()),
1150 ConstValue::Struct(v, _) => {
1151 if let [low, high] = &v[..] {
1152 Some(low.long(db).to_int()? + (high.long(db).to_int()? << 128))
1153 } else {
1154 None
1155 }
1156 }
1157 ConstValue::NonZero(const_value) => numeric_arg_value(db, *const_value),
1158 _ => None,
1159 }
1160}
1161
1162fn const_calc_info<'db>(db: &'db dyn Database) -> Arc<ConstCalcInfo<'db>> {
1164 Arc::new(ConstCalcInfo::new(db))
1165}
1166
1167#[salsa::tracked]
1169fn const_calc_info_tracked<'db>(db: &'db dyn Database) -> Arc<ConstCalcInfo<'db>> {
1170 const_calc_info(db)
1171}
1172
1173#[derive(Debug, PartialEq, Eq, salsa::Update)]
1175pub struct ConstCalcInfo<'db> {
1176 const_traits: UnorderedHashSet<TraitId<'db>>,
1178 unit_const: ConstValueId<'db>,
1180 true_const: ConstValueId<'db>,
1182 false_const: ConstValueId<'db>,
1184 panic_with_felt252: FunctionId<'db>,
1186 pub upcast_fns: UnorderedHashSet<ExternFunctionId<'db>>,
1188 pub downcast_fns: UnorderedHashMap<ExternFunctionId<'db>, bool>,
1191 unwrap_non_zero: ExternFunctionId<'db>,
1193 pub nz_fns: UnorderedHashSet<ExternFunctionId<'db>>,
1195
1196 core_info: Arc<CoreInfo<'db>>,
1197}
1198
1199impl<'db> std::ops::Deref for ConstCalcInfo<'db> {
1200 type Target = CoreInfo<'db>;
1201 fn deref(&self) -> &CoreInfo<'db> {
1202 &self.core_info
1203 }
1204}
1205
1206impl<'db> ConstCalcInfo<'db> {
1207 fn new(db: &'db dyn Database) -> Self {
1209 let core_info = db.core_info();
1210 let unit_const = ConstValue::Struct(vec![], unit_ty(db)).intern(db);
1211 let core = ModuleHelper::core(db);
1212 let bounded_int = core.submodule("internal").submodule("bounded_int");
1213 let integer = core.submodule("integer");
1214 let zeroable = core.submodule("zeroable");
1215 let starknet = core.submodule("starknet");
1216 let class_hash_module = starknet.submodule("class_hash");
1217 let contract_address_module = starknet.submodule("contract_address");
1218 Self {
1219 const_traits: FromIterator::from_iter([
1220 core_info.neg_trt,
1221 core_info.add_trt,
1222 core_info.sub_trt,
1223 core_info.mul_trt,
1224 core_info.div_trt,
1225 core_info.rem_trt,
1226 core_info.div_rem_trt,
1227 core_info.bitand_trt,
1228 core_info.bitor_trt,
1229 core_info.bitxor_trt,
1230 core_info.partialeq_trt,
1231 core_info.partialord_trt,
1232 core_info.not_trt,
1233 ]),
1234 true_const: ConstValue::Enum(true_variant(db), unit_const).intern(db),
1235 false_const: ConstValue::Enum(false_variant(db), unit_const).intern(db),
1236 unit_const,
1237 panic_with_felt252: core.function_id("panic_with_felt252", vec![]),
1238 upcast_fns: FromIterator::from_iter([
1239 bounded_int.extern_function_id("upcast"),
1240 integer.extern_function_id("u8_to_felt252"),
1241 integer.extern_function_id("u16_to_felt252"),
1242 integer.extern_function_id("u32_to_felt252"),
1243 integer.extern_function_id("u64_to_felt252"),
1244 integer.extern_function_id("u128_to_felt252"),
1245 integer.extern_function_id("i8_to_felt252"),
1246 integer.extern_function_id("i16_to_felt252"),
1247 integer.extern_function_id("i32_to_felt252"),
1248 integer.extern_function_id("i64_to_felt252"),
1249 integer.extern_function_id("i128_to_felt252"),
1250 class_hash_module.extern_function_id("class_hash_to_felt252"),
1251 contract_address_module.extern_function_id("contract_address_to_felt252"),
1252 ]),
1253 downcast_fns: FromIterator::from_iter([
1254 (bounded_int.extern_function_id("downcast"), false),
1255 (bounded_int.extern_function_id("bounded_int_trim_min"), true),
1256 (bounded_int.extern_function_id("bounded_int_trim_max"), true),
1257 (integer.extern_function_id("u8_try_from_felt252"), false),
1258 (integer.extern_function_id("u16_try_from_felt252"), false),
1259 (integer.extern_function_id("u32_try_from_felt252"), false),
1260 (integer.extern_function_id("u64_try_from_felt252"), false),
1261 (integer.extern_function_id("i8_try_from_felt252"), false),
1262 (integer.extern_function_id("i16_try_from_felt252"), false),
1263 (integer.extern_function_id("i32_try_from_felt252"), false),
1264 (integer.extern_function_id("i64_try_from_felt252"), false),
1265 (integer.extern_function_id("i128_try_from_felt252"), false),
1266 (class_hash_module.extern_function_id("class_hash_try_from_felt252"), false),
1267 (
1268 contract_address_module.extern_function_id("contract_address_try_from_felt252"),
1269 false,
1270 ),
1271 ]),
1272 unwrap_non_zero: zeroable.extern_function_id("unwrap_non_zero"),
1273 nz_fns: FromIterator::from_iter([
1274 core.extern_function_id("felt252_is_zero"),
1275 bounded_int.extern_function_id("bounded_int_is_zero"),
1276 integer.extern_function_id("u8_is_zero"),
1277 integer.extern_function_id("u16_is_zero"),
1278 integer.extern_function_id("u32_is_zero"),
1279 integer.extern_function_id("u64_is_zero"),
1280 integer.extern_function_id("u128_is_zero"),
1281 integer.extern_function_id("u256_is_zero"),
1282 ]),
1283 core_info,
1284 }
1285 }
1286}
1287
1288pub trait ConstantSemantic<'db>: Database {
1290 fn constant_semantic_diagnostics(
1292 &'db self,
1293 const_id: ConstantId<'db>,
1294 ) -> Diagnostics<'db, SemanticDiagnostic<'db>> {
1295 let db = self.as_dyn_database();
1296 constant_semantic_data(db, const_id, false)
1297 .as_ref()
1298 .map(|data| data.diagnostics.clone())
1299 .unwrap_or_default()
1300 }
1301 fn constant_semantic_data(&'db self, use_id: ConstantId<'db>) -> Maybe<Constant<'db>> {
1303 let db = self.as_dyn_database();
1304 constant_semantic_data(db, use_id, false).maybe_as_ref()?.constant.clone()
1305 }
1306 fn constant_resolver_data(&'db self, use_id: ConstantId<'db>) -> Maybe<Arc<ResolverData<'db>>> {
1308 let db = self.as_dyn_database();
1309 Ok(constant_semantic_data(db, use_id, false).maybe_as_ref()?.resolver_data.clone())
1310 }
1311 fn constant_const_value(&'db self, const_id: ConstantId<'db>) -> Maybe<ConstValueId<'db>> {
1313 let db = self.as_dyn_database();
1314 Ok(constant_semantic_data(db, const_id, false).maybe_as_ref()?.const_value)
1315 }
1316 fn const_calc_info(&'db self) -> Arc<ConstCalcInfo<'db>> {
1318 const_calc_info_tracked(self.as_dyn_database())
1319 }
1320}
1321impl<'db, T: Database + ?Sized> ConstantSemantic<'db> for T {}