1use std::sync::Arc;
2
3use cairo_lang_debug::DebugWithDb;
4use cairo_lang_defs::ids::{
5 ConstantId, GenericParamId, LanguageElementId, LookupItemId, ModuleItemId,
6 NamedLanguageElementId, TraitConstantId,
7};
8use cairo_lang_diagnostics::{DiagnosticAdded, Diagnostics, Maybe, ToMaybe, skip_diagnostic};
9use cairo_lang_proc_macros::{DebugWithDb, SemanticObject};
10use cairo_lang_syntax::node::ast::ItemConstant;
11use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
12use cairo_lang_syntax::node::{TypedStablePtr, TypedSyntaxNode};
13use cairo_lang_utils::{
14 Intern, LookupIntern, define_short_id, extract_matches, try_extract_matches,
15};
16use id_arena::Arena;
17use itertools::Itertools;
18use num_bigint::BigInt;
19use num_traits::{Num, ToPrimitive, Zero};
20use smol_str::SmolStr;
21
22use super::functions::{GenericFunctionId, GenericFunctionWithBodyId};
23use super::imp::ImplId;
24use crate::corelib::{
25 CoreTraitContext, LiteralError, core_box_ty, core_nonzero_ty, get_core_trait,
26 get_core_ty_by_name, try_extract_nz_wrapped_type, validate_literal,
27};
28use crate::db::SemanticGroup;
29use crate::diagnostic::{SemanticDiagnosticKind, SemanticDiagnostics, SemanticDiagnosticsBuilder};
30use crate::expr::compute::{
31 ComputationContext, ContextFunction, Environment, ExprAndId, compute_expr_semantic,
32};
33use crate::expr::inference::conform::InferenceConform;
34use crate::expr::inference::{ConstVar, InferenceId};
35use crate::literals::try_extract_minus_literal;
36use crate::resolve::{Resolver, ResolverData};
37use crate::substitution::SemanticRewriter;
38use crate::types::resolve_type;
39use crate::{
40 ConcreteTypeId, ConcreteVariant, Expr, ExprBlock, ExprConstant, ExprFunctionCall,
41 ExprFunctionCallArg, ExprId, ExprMemberAccess, ExprStructCtor, FunctionId, GenericParam,
42 SemanticDiagnostic, TypeId, TypeLongId, semantic_object_for_id,
43};
44
45#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
46#[debug_db(dyn SemanticGroup + 'static)]
47pub struct Constant {
48 pub value: ExprId,
50 pub exprs: Arc<Arena<Expr>>,
52}
53
54impl Constant {
55 pub fn ty(&self) -> TypeId {
56 self.exprs[self.value].ty()
57 }
58}
59
60#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
64#[debug_db(dyn SemanticGroup + 'static)]
65pub struct ConstantData {
66 pub diagnostics: Diagnostics<SemanticDiagnostic>,
67 pub constant: Maybe<Constant>,
68 pub const_value: ConstValueId,
69 pub resolver_data: Arc<ResolverData>,
70}
71
72define_short_id!(
73 ConstValueId,
74 ConstValue,
75 SemanticGroup,
76 lookup_intern_const_value,
77 intern_const_value
78);
79semantic_object_for_id!(ConstValueId, lookup_intern_const_value, intern_const_value, ConstValue);
80impl ConstValueId {
81 pub fn format(&self, db: &dyn SemanticGroup) -> String {
82 format!("{:?}", self.lookup_intern(db).debug(db.elongate()))
83 }
84
85 pub fn is_fully_concrete(&self, db: &dyn SemanticGroup) -> bool {
87 self.lookup_intern(db).is_fully_concrete(db)
88 }
89
90 pub fn is_var_free(&self, db: &dyn SemanticGroup) -> bool {
92 self.lookup_intern(db).is_var_free(db)
93 }
94
95 pub fn ty(&self, db: &dyn SemanticGroup) -> Maybe<TypeId> {
97 self.lookup_intern(db).ty(db)
98 }
99}
100
101#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
103pub enum ConstValue {
104 Int(#[dont_rewrite] BigInt, TypeId),
105 Struct(Vec<ConstValue>, TypeId),
106 Enum(ConcreteVariant, Box<ConstValue>),
107 NonZero(Box<ConstValue>),
108 Boxed(Box<ConstValue>),
109 Generic(#[dont_rewrite] GenericParamId),
110 ImplConstant(ImplConstantId),
111 TraitConstant(TraitConstantId),
112 Var(ConstVar, TypeId),
113 Missing(#[dont_rewrite] DiagnosticAdded),
115}
116impl ConstValue {
117 pub fn is_fully_concrete(&self, db: &dyn SemanticGroup) -> bool {
119 self.ty(db).unwrap().is_fully_concrete(db)
120 && match self {
121 ConstValue::Int(_, _) => true,
122 ConstValue::Struct(members, _) => {
123 members.iter().all(|member: &ConstValue| member.is_fully_concrete(db))
124 }
125 ConstValue::Enum(_, value)
126 | ConstValue::NonZero(value)
127 | ConstValue::Boxed(value) => value.is_fully_concrete(db),
128 ConstValue::Generic(_)
129 | ConstValue::Var(_, _)
130 | ConstValue::Missing(_)
131 | ConstValue::ImplConstant(_)
132 | ConstValue::TraitConstant(_) => false,
133 }
134 }
135
136 pub fn is_var_free(&self, db: &dyn SemanticGroup) -> bool {
138 self.ty(db).unwrap().is_var_free(db)
139 && match self {
140 ConstValue::Int(_, _)
141 | ConstValue::Generic(_)
142 | ConstValue::Missing(_)
143 | ConstValue::TraitConstant(_) => true,
144 ConstValue::Struct(members, _) => {
145 members.iter().all(|member| member.is_var_free(db))
146 }
147 ConstValue::Enum(_, value)
148 | ConstValue::NonZero(value)
149 | ConstValue::Boxed(value) => value.is_var_free(db),
150 ConstValue::Var(_, _) => false,
151 ConstValue::ImplConstant(impl_constant) => impl_constant.impl_id().is_var_free(db),
152 }
153 }
154
155 pub fn ty(&self, db: &dyn SemanticGroup) -> Maybe<TypeId> {
157 Ok(match self {
158 ConstValue::Int(_, ty) => *ty,
159 ConstValue::Struct(_, ty) => *ty,
160 ConstValue::Enum(variant, _) => {
161 TypeLongId::Concrete(ConcreteTypeId::Enum(variant.concrete_enum_id)).intern(db)
162 }
163 ConstValue::NonZero(value) => core_nonzero_ty(db, value.ty(db)?),
164 ConstValue::Boxed(value) => core_box_ty(db, value.ty(db)?),
165 ConstValue::Generic(param) => {
166 extract_matches!(db.generic_param_semantic(*param)?, GenericParam::Const).ty
167 }
168 ConstValue::Var(_, ty) => *ty,
169 ConstValue::Missing(_) => TypeId::missing(db, skip_diagnostic()),
170 ConstValue::ImplConstant(impl_constant_id) => {
171 db.impl_constant_concrete_implized_type(*impl_constant_id)?
172 }
173 ConstValue::TraitConstant(trait_constant) => db.trait_constant_type(*trait_constant)?,
174 })
175 }
176
177 pub fn into_int(self) -> Option<BigInt> {
179 match self {
180 ConstValue::Int(value, _) => Some(value.clone()),
181 _ => None,
182 }
183 }
184}
185
186#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
188pub struct ImplConstantId {
189 impl_id: ImplId,
191 trait_constant_id: TraitConstantId,
193}
194
195impl ImplConstantId {
196 pub fn new(
199 impl_id: ImplId,
200 trait_constant_id: TraitConstantId,
201 db: &dyn SemanticGroup,
202 ) -> Self {
203 if let crate::items::imp::ImplLongId::Concrete(concrete_impl) = impl_id.lookup_intern(db) {
204 let impl_def_id = concrete_impl.impl_def_id(db);
205 assert_eq!(Ok(trait_constant_id.trait_id(db.upcast())), db.impl_def_trait(impl_def_id));
206 }
207
208 ImplConstantId { impl_id, trait_constant_id }
209 }
210 pub fn impl_id(&self) -> ImplId {
211 self.impl_id
212 }
213 pub fn trait_constant_id(&self) -> TraitConstantId {
214 self.trait_constant_id
215 }
216
217 pub fn format(&self, db: &dyn SemanticGroup) -> SmolStr {
218 format!("{}::{}", self.impl_id.name(db.upcast()), self.trait_constant_id.name(db.upcast()))
219 .into()
220 }
221}
222impl DebugWithDb<dyn SemanticGroup> for ImplConstantId {
223 fn fmt(
224 &self,
225 f: &mut std::fmt::Formatter<'_>,
226 db: &(dyn SemanticGroup + 'static),
227 ) -> std::fmt::Result {
228 write!(f, "{}", self.format(db))
229 }
230}
231
232pub fn priv_constant_semantic_data(
234 db: &dyn SemanticGroup,
235 const_id: ConstantId,
236 in_cycle: bool,
237) -> Maybe<ConstantData> {
238 let lookup_item_id = LookupItemId::ModuleItem(ModuleItemId::Constant(const_id));
239 if in_cycle {
240 constant_semantic_data_cycle_helper(
241 db,
242 &db.module_constant_by_id(const_id)?.to_maybe()?,
243 lookup_item_id,
244 None,
245 &const_id,
246 )
247 } else {
248 constant_semantic_data_helper(
249 db,
250 &db.module_constant_by_id(const_id)?.to_maybe()?,
251 lookup_item_id,
252 None,
253 &const_id,
254 )
255 }
256}
257
258pub fn priv_constant_semantic_data_cycle(
260 db: &dyn SemanticGroup,
261 _cycle: &salsa::Cycle,
262 const_id: &ConstantId,
263 _in_cycle: &bool,
264) -> Maybe<ConstantData> {
265 priv_constant_semantic_data(db, *const_id, true)
266}
267
268pub fn constant_semantic_data_helper(
270 db: &dyn SemanticGroup,
271 constant_ast: &ItemConstant,
272 lookup_item_id: LookupItemId,
273 parent_resolver_data: Option<Arc<ResolverData>>,
274 element_id: &impl LanguageElementId,
275) -> Maybe<ConstantData> {
276 let mut diagnostics: SemanticDiagnostics = SemanticDiagnostics::default();
277 let syntax_db = db.upcast();
281
282 let inference_id = InferenceId::LookupItemDeclaration(lookup_item_id);
283
284 let mut resolver = match parent_resolver_data {
285 Some(parent_resolver_data) => {
286 Resolver::with_data(db, parent_resolver_data.clone_with_inference_id(db, inference_id))
287 }
288 None => Resolver::new(db, element_id.module_file_id(db.upcast()), inference_id),
289 };
290 resolver.set_feature_config(element_id, constant_ast, &mut diagnostics);
291
292 let constant_type = resolve_type(
293 db,
294 &mut diagnostics,
295 &mut resolver,
296 &constant_ast.type_clause(syntax_db).ty(syntax_db),
297 );
298
299 let environment = Environment::empty();
300 let mut ctx = ComputationContext::new(
301 db,
302 &mut diagnostics,
303 resolver,
304 None,
305 environment,
306 ContextFunction::Global,
307 );
308
309 let value = compute_expr_semantic(&mut ctx, &constant_ast.value(syntax_db));
310 let const_value = resolve_const_expr_and_evaluate(
311 db,
312 &mut ctx,
313 &value,
314 constant_ast.stable_ptr().untyped(),
315 constant_type,
316 )
317 .intern(db);
318
319 ctx.resolver.inference().finalize(ctx.diagnostics, constant_ast.stable_ptr().untyped());
321 ctx.apply_inference_rewriter_to_exprs();
322
323 let const_value = ctx
324 .resolver
325 .inference()
326 .rewrite(const_value)
327 .unwrap_or_else(|_| ConstValue::Missing(skip_diagnostic()).intern(db));
328 let resolver_data = Arc::new(ctx.resolver.data);
329 let constant = Constant { value: value.id, exprs: Arc::new(ctx.arenas.exprs) };
330 Ok(ConstantData {
331 diagnostics: diagnostics.build(),
332 const_value,
333 constant: Ok(constant),
334 resolver_data,
335 })
336}
337
338pub fn constant_semantic_data_cycle_helper(
340 db: &dyn SemanticGroup,
341 constant_ast: &ItemConstant,
342 lookup_item_id: LookupItemId,
343 parent_resolver_data: Option<Arc<ResolverData>>,
344 element_id: &impl LanguageElementId,
345) -> Maybe<ConstantData> {
346 let mut diagnostics: SemanticDiagnostics = SemanticDiagnostics::default();
347
348 let inference_id = InferenceId::LookupItemDeclaration(lookup_item_id);
349
350 let resolver = match parent_resolver_data {
351 Some(parent_resolver_data) => {
352 Resolver::with_data(db, parent_resolver_data.clone_with_inference_id(db, inference_id))
353 }
354 None => Resolver::new(db, element_id.module_file_id(db.upcast()), inference_id),
355 };
356
357 let resolver_data = Arc::new(resolver.data);
358
359 let diagnostic_added = diagnostics.report(constant_ast, SemanticDiagnosticKind::ConstCycle);
360 Ok(ConstantData {
361 constant: Err(diagnostic_added),
362 const_value: ConstValue::Missing(diagnostic_added).intern(db),
363 diagnostics: diagnostics.build(),
364 resolver_data,
365 })
366}
367
368pub fn resolve_const_expr_and_evaluate(
370 db: &dyn SemanticGroup,
371 ctx: &mut ComputationContext<'_>,
372 value: &ExprAndId,
373 const_stable_ptr: SyntaxStablePtrId,
374 target_type: TypeId,
375) -> ConstValue {
376 let inference = &mut ctx.resolver.inference();
377 if let Err(err_set) = inference.conform_ty(value.ty(), target_type) {
378 inference.report_on_pending_error(err_set, ctx.diagnostics, const_stable_ptr);
379 }
380
381 if let Err(err_set) = inference.solve() {
382 inference.report_on_pending_error(err_set, ctx.diagnostics, const_stable_ptr);
383 }
384
385 ctx.apply_inference_rewriter_to_exprs();
386
387 match &value.expr {
388 Expr::Constant(ExprConstant { const_value_id, .. }) => const_value_id.lookup_intern(db),
389 _ => evaluate_constant_expr(db, &ctx.arenas.exprs, value.id, ctx.diagnostics),
391 }
392}
393
394pub fn value_as_const_value(
396 db: &dyn SemanticGroup,
397 ty: TypeId,
398 value: &BigInt,
399) -> Result<ConstValue, LiteralError> {
400 validate_literal(db.upcast(), ty, value.clone())?;
401 let get_basic_const_value = |ty| {
402 let u256_ty = get_core_ty_by_name(db.upcast(), "u256".into(), vec![]);
403
404 if ty != u256_ty {
405 ConstValue::Int(value.clone(), ty)
406 } else {
407 let u128_ty = get_core_ty_by_name(db.upcast(), "u128".into(), vec![]);
408 let mask128 = BigInt::from(u128::MAX);
409 let low = value & mask128;
410 let high = value >> 128;
411 ConstValue::Struct(
412 vec![(ConstValue::Int(low, u128_ty)), (ConstValue::Int(high, u128_ty))],
413 ty,
414 )
415 }
416 };
417
418 if let Some(inner) = try_extract_nz_wrapped_type(db.upcast(), ty) {
419 Ok(ConstValue::NonZero(Box::new(get_basic_const_value(inner))))
420 } else {
421 Ok(get_basic_const_value(ty))
422 }
423}
424
425pub fn evaluate_constant_expr(
427 db: &dyn SemanticGroup,
428 exprs: &Arena<Expr>,
429 expr_id: ExprId,
430 diagnostics: &mut SemanticDiagnostics,
431) -> ConstValue {
432 let expr = &exprs[expr_id];
433
434 match expr {
435 Expr::Constant(expr) => expr.const_value_id.lookup_intern(db),
436 Expr::Block(ExprBlock { statements, tail: Some(inner), .. }) if statements.is_empty() => {
437 evaluate_constant_expr(db, exprs, *inner, diagnostics)
438 }
439 Expr::FunctionCall(expr) => evaluate_const_function_call(db, exprs, expr, diagnostics)
440 .map(|value| {
441 value_as_const_value(db, expr.ty, &value)
442 .map_err(|err| {
443 diagnostics.report(
444 expr.stable_ptr.untyped(),
445 SemanticDiagnosticKind::LiteralError(err),
446 )
447 })
448 .unwrap_or_else(ConstValue::Missing)
449 })
450 .unwrap_or_else(ConstValue::Missing),
451 Expr::Literal(expr) => value_as_const_value(db, expr.ty, &expr.value)
452 .map_err(|err| {
453 diagnostics
454 .report(expr.stable_ptr.untyped(), SemanticDiagnosticKind::LiteralError(err))
455 })
456 .unwrap_or_else(ConstValue::Missing),
457 Expr::Tuple(expr) => ConstValue::Struct(
458 expr.items
459 .iter()
460 .map(|expr_id| evaluate_constant_expr(db, exprs, *expr_id, diagnostics))
461 .collect(),
462 expr.ty,
463 ),
464 Expr::StructCtor(ExprStructCtor {
465 members,
466 base_struct: None,
467 ty,
468 concrete_struct_id,
469 ..
470 }) => {
471 let member_order = match db.concrete_struct_members(*concrete_struct_id) {
472 Ok(member_order) => member_order,
473 Err(diag_add) => return ConstValue::Missing(diag_add),
474 };
475 ConstValue::Struct(
476 member_order
477 .values()
478 .map(|m| {
479 members
480 .iter()
481 .find(|(member_id, _)| m.id == *member_id)
482 .map(|(_, expr_id)| {
483 evaluate_constant_expr(db, exprs, *expr_id, diagnostics)
484 })
485 .unwrap_or_else(|| ConstValue::Missing(skip_diagnostic()))
486 })
487 .collect(),
488 *ty,
489 )
490 }
491 Expr::EnumVariantCtor(expr) => ConstValue::Enum(
492 expr.variant.clone(),
493 Box::new(evaluate_constant_expr(db, exprs, expr.value_expr, diagnostics)),
494 ),
495 Expr::MemberAccess(expr) => extract_const_member_access(db, exprs, expr, diagnostics)
496 .unwrap_or_else(ConstValue::Missing),
497 Expr::FixedSizeArray(expr) => ConstValue::Struct(
498 match &expr.items {
499 crate::FixedSizeArrayItems::Items(items) => items
500 .iter()
501 .map(|expr_id| evaluate_constant_expr(db, exprs, *expr_id, diagnostics))
502 .collect(),
503 crate::FixedSizeArrayItems::ValueAndSize(value, count) => {
504 let value = evaluate_constant_expr(db, exprs, *value, diagnostics);
505 let count = count.lookup_intern(db);
506 if let Some(count) = count.into_int() {
507 (0..count.to_usize().unwrap()).map(|_| value.clone()).collect()
508 } else {
509 diagnostics.report(
510 expr.stable_ptr.untyped(),
511 SemanticDiagnosticKind::UnsupportedConstant,
512 );
513 vec![]
514 }
515 }
516 },
517 expr.ty,
518 ),
519 _ if diagnostics.error_count == 0 => ConstValue::Missing(
520 diagnostics
521 .report(expr.stable_ptr().untyped(), SemanticDiagnosticKind::UnsupportedConstant),
522 ),
523 _ => ConstValue::Missing(skip_diagnostic()),
524 }
525}
526
527fn is_function_const(db: &dyn SemanticGroup, function_id: FunctionId) -> bool {
529 let concrete_function = function_id.get_concrete(db);
530 let Ok(Some(body)) = concrete_function.body(db) else { return false };
531 let GenericFunctionWithBodyId::Impl(imp) = body.generic_function(db) else { return false };
532 let impl_def = imp.concrete_impl_id.impl_def_id(db);
533 if impl_def.parent_module(db.upcast()).owning_crate(db.upcast()) != db.core_crate() {
534 return false;
535 }
536 let Ok(trait_id) = db.impl_def_trait(impl_def) else {
537 return false;
538 };
539 let expected_trait_name = match imp.function_body.name(db.upcast()).as_str() {
540 "neg" => "Neg",
541 "add" => "Add",
542 "sub" => "Sub",
543 "mul" => "Mul",
544 "div" => "Div",
545 "rem" => "Rem",
546 "bitand" => "BitAnd",
547 "bitor" => "BitOr",
548 "bitxor" => "BitXor",
549 _ => return false,
550 };
551 trait_id == get_core_trait(db, CoreTraitContext::TopLevel, expected_trait_name.into())
552}
553
554fn evaluate_const_function_call(
556 db: &dyn SemanticGroup,
557 exprs: &Arena<Expr>,
558 expr: &ExprFunctionCall,
559 diagnostics: &mut SemanticDiagnostics,
560) -> Maybe<BigInt> {
561 if let Some(value) = try_extract_minus_literal(db.upcast(), exprs, expr) {
562 return Ok(value);
563 }
564 let args = expr
565 .args
566 .iter()
567 .filter_map(|arg| try_extract_matches!(arg, ExprFunctionCallArg::Value))
568 .map(|arg| {
569 match evaluate_constant_expr(db, exprs, *arg, diagnostics) {
570 ConstValue::Int(v, _ty) => Ok(v),
571 ConstValue::Struct(v, _) => {
573 if let [ConstValue::Int(low, _), ConstValue::Int(high, _)] = &v[..] {
574 Ok(low + (high << 128))
575 } else {
576 Err(diagnostics.report(
577 exprs[*arg].stable_ptr().untyped(),
578 SemanticDiagnosticKind::UnsupportedConstant,
579 ))
580 }
581 }
582 ConstValue::Missing(err) => Err(err),
583 _ => Err(diagnostics.report(
584 exprs[*arg].stable_ptr().untyped(),
585 SemanticDiagnosticKind::UnsupportedConstant,
586 )),
587 }
588 })
589 .collect_vec()
590 .into_iter()
591 .collect::<Result<Vec<_>, _>>()?;
592
593 if !is_function_const(db, expr.function) {
594 return Err(diagnostics
595 .report(expr.stable_ptr.untyped(), SemanticDiagnosticKind::UnsupportedConstant));
596 }
597
598 let imp = extract_matches!(
599 expr.function.get_concrete(db.upcast()).generic_function,
600 GenericFunctionId::Impl
601 );
602 let is_felt252_ty = expr.ty == db.core_felt252_ty();
603 let mut value = match imp.function.name(db.upcast()).as_str() {
604 "neg" => -&args[0],
605 "add" => &args[0] + &args[1],
606 "sub" => &args[0] - &args[1],
607 "mul" => &args[0] * &args[1],
608 "div" | "rem" if args[1].is_zero() => {
609 return Err(diagnostics
610 .report(expr.stable_ptr.untyped(), SemanticDiagnosticKind::DivisionByZero));
611 }
612 "div" if !is_felt252_ty => &args[0] / &args[1],
613 "rem" if !is_felt252_ty => &args[0] % &args[1],
614 "bitand" if !is_felt252_ty => &args[0] & &args[1],
615 "bitor" if !is_felt252_ty => &args[0] | &args[1],
616 "bitxor" if !is_felt252_ty => &args[0] ^ &args[1],
617 _ => unreachable!("Unexpected function call in constant lowering: {:?}", expr),
618 };
619 if is_felt252_ty {
620 value %= BigInt::from_str_radix(
622 "800000000000011000000000000000000000000000000000000000000000001",
623 16,
624 )
625 .unwrap();
626 }
627 Ok(value)
628}
629
630fn extract_const_member_access(
632 db: &dyn SemanticGroup,
633 exprs: &Arena<Expr>,
634 expr: &ExprMemberAccess,
635 diagnostics: &mut SemanticDiagnostics,
636) -> Maybe<ConstValue> {
637 let full_struct = evaluate_constant_expr(db, exprs, expr.expr, diagnostics);
638 let ConstValue::Struct(mut values, _) = full_struct else {
639 return Err(diagnostics.report(
640 exprs[expr.expr].stable_ptr().untyped(),
641 SemanticDiagnosticKind::UnsupportedConstant,
642 ));
643 };
644 let members = db.concrete_struct_members(expr.concrete_struct_id)?;
645 let Some(member_idx) = members.iter().position(|(_, member)| member.id == expr.member) else {
646 return Err(diagnostics.report(
647 exprs[expr.expr].stable_ptr().untyped(),
648 SemanticDiagnosticKind::UnsupportedConstant,
649 ));
650 };
651 Ok(values.swap_remove(member_idx))
652}
653
654pub fn constant_semantic_diagnostics(
656 db: &dyn SemanticGroup,
657 const_id: ConstantId,
658) -> Diagnostics<SemanticDiagnostic> {
659 db.priv_constant_semantic_data(const_id, false).map(|data| data.diagnostics).unwrap_or_default()
660}
661
662pub fn constant_semantic_data(db: &dyn SemanticGroup, const_id: ConstantId) -> Maybe<Constant> {
664 db.priv_constant_semantic_data(const_id, false)?.constant
665}
666
667pub fn constant_semantic_data_cycle(
669 db: &dyn SemanticGroup,
670 _cycle: &salsa::Cycle,
671 const_id: &ConstantId,
672) -> Maybe<Constant> {
673 db.priv_constant_semantic_data(*const_id, true)?.constant
675}
676
677pub fn constant_resolver_data(
679 db: &dyn SemanticGroup,
680 const_id: ConstantId,
681) -> Maybe<Arc<ResolverData>> {
682 Ok(db.priv_constant_semantic_data(const_id, false)?.resolver_data)
683}
684
685pub fn constant_resolver_data_cycle(
687 db: &dyn SemanticGroup,
688 _cycle: &salsa::Cycle,
689 const_id: &ConstantId,
690) -> Maybe<Arc<ResolverData>> {
691 Ok(db.priv_constant_semantic_data(*const_id, true)?.resolver_data)
692}
693
694pub fn constant_const_value(db: &dyn SemanticGroup, const_id: ConstantId) -> Maybe<ConstValueId> {
696 Ok(db.priv_constant_semantic_data(const_id, false)?.const_value)
697}
698
699pub fn constant_const_value_cycle(
701 db: &dyn SemanticGroup,
702 _cycle: &salsa::Cycle,
703 const_id: &ConstantId,
704) -> Maybe<ConstValueId> {
705 Ok(db.priv_constant_semantic_data(*const_id, true)?.const_value)
707}
708
709pub fn constant_const_type(db: &dyn SemanticGroup, const_id: ConstantId) -> Maybe<TypeId> {
711 db.priv_constant_semantic_data(const_id, false)?.const_value.ty(db)
712}
713
714pub fn constant_const_type_cycle(
716 db: &dyn SemanticGroup,
717 _cycle: &salsa::Cycle,
718 const_id: &ConstantId,
719) -> Maybe<TypeId> {
720 db.priv_constant_semantic_data(*const_id, true)?.const_value.ty(db)
722}