use std::sync::Arc;
use cairo_lang_defs::ids::{ConstantId, LanguageElementId};
use cairo_lang_diagnostics::{Diagnostics, Maybe, ToMaybe};
use cairo_lang_proc_macros::{DebugWithDb, SemanticObject};
use cairo_lang_syntax::node::TypedSyntaxNode;
use crate::db::SemanticGroup;
use crate::diagnostic::SemanticDiagnostics;
use crate::expr::compute::{compute_expr_semantic, ComputationContext, Environment};
use crate::resolve::{ResolvedItems, Resolver};
use crate::substitution::SemanticRewriter;
use crate::types::resolve_type;
use crate::{Expr, SemanticDiagnostic};
#[cfg(test)]
#[path = "constant_test.rs"]
mod test;
#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, SemanticObject)]
#[debug_db(dyn SemanticGroup + 'static)]
pub struct Constant {
pub value: Expr,
}
#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
#[debug_db(dyn SemanticGroup + 'static)]
pub struct ConstantData {
diagnostics: Diagnostics<SemanticDiagnostic>,
constant: Constant,
resolved_lookback: Arc<ResolvedItems>,
}
pub fn priv_constant_semantic_data(
db: &dyn SemanticGroup,
const_id: ConstantId,
) -> Maybe<ConstantData> {
let module_file_id = const_id.module_file_id(db.upcast());
let mut diagnostics = SemanticDiagnostics::new(module_file_id);
let module_constants = db.module_constants(module_file_id.0)?;
let const_ast = module_constants.get(&const_id).to_maybe()?;
let syntax_db = db.upcast();
let mut resolver = Resolver::new(db, module_file_id);
let const_type = resolve_type(
db,
&mut diagnostics,
&mut resolver,
&const_ast.type_clause(syntax_db).ty(syntax_db),
);
let mut ctx =
ComputationContext::new(db, &mut diagnostics, resolver, None, Environment::default());
let value = compute_expr_semantic(&mut ctx, &const_ast.value(syntax_db));
if let Err(err) = ctx.resolver.inference.conform_ty(value.ty(), const_type) {
err.report(ctx.diagnostics, const_ast.stable_ptr().untyped());
}
if !matches!(value, Expr::Literal(_)) {
ctx.diagnostics.report(
&const_ast.value(syntax_db),
crate::diagnostic::SemanticDiagnosticKind::OnlyLiteralConstants,
);
};
let constant = Constant { value };
let resolved_lookback = Arc::new(ctx.resolver.resolved_items);
if let Some((stable_ptr, inference_err)) = ctx.resolver.inference.finalize() {
inference_err.report(ctx.diagnostics, stable_ptr);
}
let constant = ctx
.resolver
.inference
.rewrite(constant)
.map_err(|err| err.report(&mut diagnostics, const_ast.stable_ptr().untyped()))?;
Ok(ConstantData { diagnostics: diagnostics.build(), constant, resolved_lookback })
}
pub fn constant_semantic_diagnostics(
db: &dyn SemanticGroup,
const_id: ConstantId,
) -> Diagnostics<SemanticDiagnostic> {
db.priv_constant_semantic_data(const_id).map(|data| data.diagnostics).unwrap_or_default()
}
pub fn constant_semantic_data(db: &dyn SemanticGroup, const_id: ConstantId) -> Maybe<Constant> {
Ok(db.priv_constant_semantic_data(const_id)?.constant)
}
pub fn constant_resolved_lookback(
db: &dyn SemanticGroup,
const_id: ConstantId,
) -> Maybe<Arc<ResolvedItems>> {
Ok(db.priv_constant_semantic_data(const_id)?.resolved_lookback)
}