use mago_atom::atom;
use mago_codex::scanner::inference::get_literal_constant_type;
use mago_codex::scanner::inference::get_platform_constant_type;
use mago_codex::ttype::expander;
use mago_codex::ttype::expander::TypeExpansionOptions;
use mago_codex::ttype::get_mixed;
use mago_reporting::Annotation;
use mago_reporting::Issue;
use mago_span::HasSpan;
use mago_syntax::ast::ConstantAccess;
use crate::analyzable::Analyzable;
use crate::artifacts::AnalysisArtifacts;
use crate::code::IssueCode;
use crate::context::Context;
use crate::context::block::BlockContext;
use crate::error::AnalysisError;
impl<'arena> Analyzable<'_, 'arena> for ConstantAccess<'arena> {
fn analyze<'ctx>(
&self,
context: &mut Context<'ctx, 'arena>,
block_context: &mut BlockContext<'ctx>,
artifacts: &mut AnalysisArtifacts,
) -> Result<(), AnalysisError> {
let name = context.resolved_names.get(self);
let unqualified_name = self.name.value();
let constant_metadata =
context.codebase.get_constant(name).or_else(|| context.codebase.get_constant(unqualified_name));
let Some(constant_metadata) = constant_metadata else {
if let Some(literal_type) = get_literal_constant_type(name) {
artifacts.set_expression_type(self, literal_type);
return Ok(());
}
let is_known = block_context.known_constants.contains(&atom(name));
if is_known {
artifacts.set_expression_type(self, get_mixed());
} else {
context.collector.report_with_code(
IssueCode::NonExistentConstant,
Issue::error(format!(
"Undefined constant: `{name}`."
))
.with_annotation(
Annotation::primary(self.span())
.with_message(format!("Constant `{name}` is not defined."))
)
.with_note(
"The constant might be misspelled, not defined, or not imported."
)
.with_help(
format!(
"Define the constant `{name}` using `define()` or `const`, or check for typos and ensure it's available in this scope."
)
),
);
}
return Ok(());
};
if constant_metadata.flags.is_deprecated() {
context.collector.report_with_code(
IssueCode::DeprecatedConstant,
Issue::warning(format!("Using deprecated constant: `{name}`."))
.with_annotation(Annotation::primary(self.span()).with_message("This constant is deprecated."))
.with_note("Consider using an alternative constant or variable.")
.with_help("Check `{name}` documentation for alternatives or updates."),
);
}
crate::utils::experimental::check_experimental_constant(
context,
block_context,
&constant_metadata.flags,
name,
self.span(),
);
let mut constant_type = if let Some(t) = get_platform_constant_type(name) {
t
} else {
match &constant_metadata.type_metadata {
Some(t) => t.type_union.clone(),
None => match &constant_metadata.inferred_type {
Some(t) => t.clone(),
_ => get_mixed(),
},
}
};
expander::expand_union(context.codebase, &mut constant_type, &TypeExpansionOptions::default());
artifacts.set_expression_type(self, constant_type);
Ok(())
}
}