use std::sync::Arc;
use cairo_lang_defs::ids::{ImplAliasId, LanguageElementId};
use cairo_lang_diagnostics::{Diagnostics, Maybe, ToMaybe};
use cairo_lang_proc_macros::DebugWithDb;
use cairo_lang_syntax::node::TypedSyntaxNode;
use cairo_lang_utils::try_extract_matches;
use super::generics::{semantic_generic_params, GenericParamsData};
use super::imp::ImplId;
use crate::db::SemanticGroup;
use crate::diagnostic::SemanticDiagnosticKind::*;
use crate::diagnostic::{NotFoundItemType, SemanticDiagnostics};
use crate::expr::inference::canonic::ResultNoErrEx;
use crate::resolve::{ResolvedConcreteItem, Resolver, ResolverData};
use crate::substitution::SemanticRewriter;
use crate::{GenericParam, SemanticDiagnostic};
#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
#[debug_db(dyn SemanticGroup + 'static)]
pub struct ImplAliasData {
diagnostics: Diagnostics<SemanticDiagnostic>,
resolved_impl: Maybe<ImplId>,
generic_params: Vec<GenericParam>,
resolver_data: Arc<ResolverData>,
}
impl ImplAliasData {
pub fn check_no_cycle(&self) -> Maybe<()> {
self.resolved_impl?;
Ok(())
}
}
pub fn priv_impl_alias_semantic_data(
db: &(dyn SemanticGroup),
impl_alias_id: ImplAliasId,
) -> Maybe<ImplAliasData> {
let module_file_id = impl_alias_id.module_file_id(db.upcast());
let mut diagnostics = SemanticDiagnostics::new(module_file_id);
let module_impl_aliases = db.module_impl_aliases(module_file_id.0)?;
let impl_alias_ast = module_impl_aliases.get(&impl_alias_id).to_maybe()?;
let syntax_db = db.upcast();
let generic_params_data = db.impl_alias_generic_params_data(impl_alias_id)?;
let generic_params = generic_params_data.generic_params.clone();
let mut resolver = Resolver::with_data(db, (*generic_params_data.resolver_data).clone());
diagnostics.diagnostics.extend(generic_params_data.diagnostics);
let item = resolver.resolve_concrete_path(
&mut diagnostics,
&impl_alias_ast.impl_path(syntax_db),
NotFoundItemType::Impl,
);
let resolved_impl = item.and_then(|item| {
try_extract_matches!(item, ResolvedConcreteItem::Impl)
.ok_or_else(|| diagnostics.report(&impl_alias_ast.impl_path(syntax_db), UnknownImpl))
});
if let Some((stable_ptr, inference_err)) = resolver.inference().finalize() {
inference_err
.report(&mut diagnostics, stable_ptr.unwrap_or(impl_alias_ast.stable_ptr().untyped()));
}
let resolved_impl = resolver.inference().rewrite(resolved_impl).no_err();
let resolver_data = Arc::new(resolver.data);
Ok(ImplAliasData {
diagnostics: diagnostics.build(),
resolved_impl,
generic_params,
resolver_data,
})
}
pub fn priv_impl_alias_semantic_data_cycle(
db: &dyn SemanticGroup,
_cycle: &[String],
impl_alias_id: &ImplAliasId,
) -> Maybe<ImplAliasData> {
let module_file_id = impl_alias_id.module_file_id(db.upcast());
let mut diagnostics = SemanticDiagnostics::new(module_file_id);
let module_impl_aliases = db.module_impl_aliases(module_file_id.0)?;
let impl_alias_ast = module_impl_aliases.get(impl_alias_id).to_maybe()?;
let syntax_db = db.upcast();
let err = Err(diagnostics.report(&impl_alias_ast.name(syntax_db), ImplAliasCycle));
let generic_params_data = db.impl_alias_generic_params_data(*impl_alias_id)?;
let generic_params = generic_params_data.generic_params.clone();
diagnostics.diagnostics.extend(generic_params_data.diagnostics);
Ok(ImplAliasData {
diagnostics: diagnostics.build(),
resolved_impl: err,
generic_params,
resolver_data: Arc::new(ResolverData::new(module_file_id)),
})
}
pub fn impl_alias_semantic_diagnostics(
db: &dyn SemanticGroup,
impl_alias_id: ImplAliasId,
) -> Diagnostics<SemanticDiagnostic> {
db.priv_impl_alias_semantic_data(impl_alias_id).map(|data| data.diagnostics).unwrap_or_default()
}
pub fn impl_alias_resolved_impl(
db: &dyn SemanticGroup,
impl_alias_id: ImplAliasId,
) -> Maybe<ImplId> {
db.priv_impl_alias_semantic_data(impl_alias_id)?.resolved_impl
}
pub fn impl_alias_generic_params(
db: &dyn SemanticGroup,
impl_alias_id: ImplAliasId,
) -> Maybe<Vec<GenericParam>> {
Ok(db.impl_alias_generic_params_data(impl_alias_id)?.generic_params)
}
pub fn impl_alias_generic_params_data(
db: &dyn SemanticGroup,
impl_alias_id: ImplAliasId,
) -> Maybe<GenericParamsData> {
let module_file_id = impl_alias_id.module_file_id(db.upcast());
let mut diagnostics = SemanticDiagnostics::new(module_file_id);
let module_impl_aliases = db.module_impl_aliases(module_file_id.0)?;
let impl_alias_ast = module_impl_aliases.get(&impl_alias_id).to_maybe()?;
let syntax_db = db.upcast();
let mut resolver = Resolver::new(db, module_file_id);
let generic_params = semantic_generic_params(
db,
&mut diagnostics,
&mut resolver,
module_file_id,
&impl_alias_ast.generic_params(syntax_db),
)?;
let generic_params = resolver.inference().rewrite(generic_params).no_err();
resolver.inference().finalize().map(|(_, inference_err)| {
inference_err.report(&mut diagnostics, impl_alias_ast.stable_ptr().untyped())
});
let resolver_data = Arc::new(resolver.data);
Ok(GenericParamsData { diagnostics: diagnostics.build(), generic_params, resolver_data })
}
pub fn impl_alias_resolver_data(
db: &dyn SemanticGroup,
impl_alias_id: ImplAliasId,
) -> Maybe<Arc<ResolverData>> {
Ok(db.priv_impl_alias_semantic_data(impl_alias_id)?.resolver_data)
}