cairo_lang_semantic/items/
impl_alias.rs

1use std::sync::Arc;
2
3use cairo_lang_defs::ids::{
4    ImplAliasId, ImplDefId, LanguageElementId, LookupItemId, ModuleFileId, ModuleItemId,
5};
6use cairo_lang_diagnostics::{Diagnostics, Maybe, ToMaybe, skip_diagnostic};
7use cairo_lang_proc_macros::DebugWithDb;
8use cairo_lang_syntax::attribute::structured::{Attribute, AttributeListStructurize};
9use cairo_lang_syntax::node::{TypedStablePtr, TypedSyntaxNode, ast};
10use cairo_lang_utils::try_extract_matches;
11
12use super::generics::{GenericParamsData, semantic_generic_params};
13use super::imp::ImplId;
14use crate::db::SemanticGroup;
15use crate::diagnostic::SemanticDiagnosticKind::*;
16use crate::diagnostic::{NotFoundItemType, SemanticDiagnostics, SemanticDiagnosticsBuilder};
17use crate::expr::inference::InferenceId;
18use crate::expr::inference::canonic::ResultNoErrEx;
19use crate::resolve::{ResolvedConcreteItem, ResolvedGenericItem, Resolver, ResolverData};
20use crate::substitution::SemanticRewriter;
21use crate::{GenericParam, SemanticDiagnostic};
22
23#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
24#[debug_db(dyn SemanticGroup + 'static)]
25pub struct ImplAliasData {
26    pub diagnostics: Diagnostics<SemanticDiagnostic>,
27    pub resolved_impl: Maybe<ImplId>,
28    generic_params: Vec<GenericParam>,
29    attributes: Vec<Attribute>,
30    pub resolver_data: Arc<ResolverData>,
31}
32
33/// Query implementation of [crate::db::SemanticGroup::priv_impl_alias_semantic_data].
34pub fn priv_impl_alias_semantic_data(
35    db: &(dyn SemanticGroup),
36    impl_alias_id: ImplAliasId,
37    in_cycle: bool,
38) -> Maybe<ImplAliasData> {
39    let lookup_item_id = LookupItemId::ModuleItem(ModuleItemId::ImplAlias(impl_alias_id));
40    let impl_alias_ast = db.module_impl_alias_by_id(impl_alias_id)?.to_maybe()?;
41
42    let generic_params_data = db.impl_alias_generic_params_data(impl_alias_id)?;
43
44    if in_cycle {
45        impl_alias_semantic_data_cycle_helper(
46            db,
47            &impl_alias_ast,
48            lookup_item_id,
49            generic_params_data,
50        )
51    } else {
52        impl_alias_semantic_data_helper(db, &impl_alias_ast, lookup_item_id, generic_params_data)
53    }
54}
55
56/// An helper function to compute the semantic data of an impl-alias item.
57pub fn impl_alias_semantic_data_helper(
58    db: &(dyn SemanticGroup),
59    impl_alias_ast: &ast::ItemImplAlias,
60    lookup_item_id: LookupItemId,
61    generic_params_data: GenericParamsData,
62) -> Maybe<ImplAliasData> {
63    let mut diagnostics = SemanticDiagnostics::default();
64    // TODO(spapini): when code changes in a file, all the AST items change (as they contain a path
65    // to the green root that changes. Once ASTs are rooted on items, use a selector that picks only
66    // the item instead of all the module data.
67    // TODO(spapini): Add generic args when they are supported on structs.
68    let syntax_db = db.upcast();
69    let inference_id = InferenceId::LookupItemDeclaration(lookup_item_id);
70    let mut resolver = Resolver::with_data(
71        db,
72        (*generic_params_data.resolver_data).clone_with_inference_id(db, inference_id),
73    );
74    diagnostics.extend(generic_params_data.diagnostics);
75
76    let item = resolver.resolve_concrete_path(
77        &mut diagnostics,
78        &impl_alias_ast.impl_path(syntax_db),
79        NotFoundItemType::Impl,
80    );
81    let resolved_impl = item.and_then(|item| {
82        try_extract_matches!(item, ResolvedConcreteItem::Impl)
83            .ok_or_else(|| diagnostics.report(&impl_alias_ast.impl_path(syntax_db), UnknownImpl))
84    });
85
86    // Check fully resolved.
87    let inference = &mut resolver.inference();
88    inference.finalize(&mut diagnostics, impl_alias_ast.stable_ptr().untyped());
89
90    let resolved_impl = inference.rewrite(resolved_impl).no_err();
91    let generic_params = inference.rewrite(generic_params_data.generic_params.clone()).no_err();
92
93    let attributes = impl_alias_ast.attributes(syntax_db).structurize(syntax_db);
94    let resolver_data = Arc::new(resolver.data);
95    Ok(ImplAliasData {
96        diagnostics: diagnostics.build(),
97        resolved_impl,
98        generic_params,
99        attributes,
100        resolver_data,
101    })
102}
103
104/// Cycle handling for [crate::db::SemanticGroup::priv_impl_alias_semantic_data].
105pub fn priv_impl_alias_semantic_data_cycle(
106    db: &dyn SemanticGroup,
107    _cycle: &salsa::Cycle,
108    impl_alias_id: &ImplAliasId,
109    _in_cycle: &bool,
110) -> Maybe<ImplAliasData> {
111    priv_impl_alias_semantic_data(db, *impl_alias_id, true)
112}
113
114/// An helper function to compute the semantic data of an impl-alias item when a cycle is detected.
115pub fn impl_alias_semantic_data_cycle_helper(
116    db: &(dyn SemanticGroup),
117    impl_alias_ast: &ast::ItemImplAlias,
118    lookup_item_id: LookupItemId,
119    generic_params_data: GenericParamsData,
120) -> Maybe<ImplAliasData> {
121    let mut diagnostics = SemanticDiagnostics::default();
122    // TODO(spapini): when code changes in a file, all the AST items change (as they contain a path
123    // to the green root that changes. Once ASTs are rooted on items, use a selector that picks only
124    // the item instead of all the module data.
125    // TODO(spapini): Add generic args when they are supported on structs.
126    let syntax_db = db.upcast();
127    let err = Err(diagnostics.report(&impl_alias_ast.name(syntax_db), ImplAliasCycle));
128    let generic_params = generic_params_data.generic_params.clone();
129    diagnostics.extend(generic_params_data.diagnostics);
130    let inference_id = InferenceId::LookupItemDeclaration(lookup_item_id);
131    let attributes = impl_alias_ast.attributes(syntax_db).structurize(syntax_db);
132    Ok(ImplAliasData {
133        diagnostics: diagnostics.build(),
134        resolved_impl: err,
135        generic_params,
136        attributes,
137        resolver_data: (*generic_params_data.resolver_data)
138            .clone_with_inference_id(db, inference_id)
139            .into(),
140    })
141}
142
143/// Query implementation of [crate::db::SemanticGroup::impl_alias_semantic_diagnostics].
144pub fn impl_alias_semantic_diagnostics(
145    db: &dyn SemanticGroup,
146    impl_alias_id: ImplAliasId,
147) -> Diagnostics<SemanticDiagnostic> {
148    db.priv_impl_alias_semantic_data(impl_alias_id, false)
149        .map(|data| data.diagnostics)
150        .unwrap_or_default()
151}
152
153/// Query implementation of [crate::db::SemanticGroup::impl_alias_resolved_impl].
154pub fn impl_alias_resolved_impl(
155    db: &dyn SemanticGroup,
156    impl_alias_id: ImplAliasId,
157) -> Maybe<ImplId> {
158    db.priv_impl_alias_semantic_data(impl_alias_id, false)?.resolved_impl
159}
160
161/// Trivial cycle handling for [crate::db::SemanticGroup::impl_alias_resolved_impl].
162pub fn impl_alias_resolved_impl_cycle(
163    db: &dyn SemanticGroup,
164    _cycle: &salsa::Cycle,
165    impl_alias_id: &ImplAliasId,
166) -> Maybe<ImplId> {
167    // Forwarding (not as a query) cycle handling to `priv_impl_alias_semantic_data` cycle handler.
168    db.priv_impl_alias_semantic_data(*impl_alias_id, true)?.resolved_impl
169}
170
171/// Query implementation of [crate::db::SemanticGroup::impl_alias_generic_params].
172pub fn impl_alias_generic_params(
173    db: &dyn SemanticGroup,
174    impl_alias_id: ImplAliasId,
175) -> Maybe<Vec<GenericParam>> {
176    Ok(db.impl_alias_generic_params_data(impl_alias_id)?.generic_params)
177}
178
179/// Query implementation of [crate::db::SemanticGroup::impl_alias_generic_params_data].
180pub fn impl_alias_generic_params_data(
181    db: &dyn SemanticGroup,
182    impl_alias_id: ImplAliasId,
183) -> Maybe<GenericParamsData> {
184    let module_file_id = impl_alias_id.module_file_id(db.upcast());
185    let impl_alias_ast = db.module_impl_alias_by_id(impl_alias_id)?.to_maybe()?;
186    impl_alias_generic_params_data_helper(
187        db,
188        module_file_id,
189        &impl_alias_ast,
190        LookupItemId::ModuleItem(ModuleItemId::ImplAlias(impl_alias_id)),
191        None,
192    )
193}
194
195/// Computes data about the generic parameters of an impl-alias item.
196pub fn impl_alias_generic_params_data_helper(
197    db: &dyn SemanticGroup,
198    module_file_id: ModuleFileId,
199    impl_alias_ast: &ast::ItemImplAlias,
200    lookup_item_id: LookupItemId,
201    parent_resolver_data: Option<Arc<ResolverData>>,
202) -> Maybe<GenericParamsData> {
203    let mut diagnostics = SemanticDiagnostics::default();
204    let inference_id = InferenceId::LookupItemGenerics(lookup_item_id);
205
206    let mut resolver = match parent_resolver_data {
207        Some(parent_resolver_data) => {
208            Resolver::with_data(db, parent_resolver_data.clone_with_inference_id(db, inference_id))
209        }
210        None => Resolver::new(db, module_file_id, inference_id),
211    };
212    resolver.set_feature_config(&lookup_item_id, impl_alias_ast, &mut diagnostics);
213    let generic_params = semantic_generic_params(
214        db,
215        &mut diagnostics,
216        &mut resolver,
217        module_file_id,
218        &impl_alias_ast.generic_params(db.upcast()),
219    );
220
221    let inference = &mut resolver.inference();
222    inference.finalize(&mut diagnostics, impl_alias_ast.stable_ptr().untyped());
223
224    let generic_params = inference.rewrite(generic_params).no_err();
225    let resolver_data = Arc::new(resolver.data);
226    Ok(GenericParamsData { diagnostics: diagnostics.build(), generic_params, resolver_data })
227}
228
229/// Query implementation of [crate::db::SemanticGroup::impl_alias_resolver_data].
230pub fn impl_alias_resolver_data(
231    db: &dyn SemanticGroup,
232    impl_alias_id: ImplAliasId,
233) -> Maybe<Arc<ResolverData>> {
234    Ok(db.priv_impl_alias_semantic_data(impl_alias_id, false)?.resolver_data)
235}
236
237/// Trivial cycle handling for [crate::db::SemanticGroup::impl_alias_resolver_data].
238pub fn impl_alias_resolver_data_cycle(
239    db: &dyn SemanticGroup,
240    _cycle: &salsa::Cycle,
241    impl_alias_id: &ImplAliasId,
242) -> Maybe<Arc<ResolverData>> {
243    // Forwarding (not as a query) cycle handling to `priv_impl_alias_semantic_data` cycle handler.
244    impl_alias_resolver_data(db, *impl_alias_id)
245}
246
247/// Query implementation of [crate::db::SemanticGroup::impl_alias_attributes].
248pub fn impl_alias_attributes(
249    db: &dyn SemanticGroup,
250    impl_alias_id: ImplAliasId,
251) -> Maybe<Vec<Attribute>> {
252    Ok(db.priv_impl_alias_semantic_data(impl_alias_id, false)?.attributes)
253}
254
255/// Query implementation of [crate::db::SemanticGroup::impl_alias_impl_def].
256pub fn impl_alias_impl_def(db: &dyn SemanticGroup, impl_alias_id: ImplAliasId) -> Maybe<ImplDefId> {
257    let module_file_id = impl_alias_id.module_file_id(db.upcast());
258    let mut diagnostics = SemanticDiagnostics::default();
259    let impl_alias_ast = db.module_impl_alias_by_id(impl_alias_id)?.to_maybe()?;
260    let inference_id = InferenceId::ImplAliasImplDef(impl_alias_id);
261
262    let mut resolver = Resolver::new(db, module_file_id, inference_id);
263    resolver.set_feature_config(&impl_alias_id, &impl_alias_ast, &mut diagnostics);
264
265    let impl_path_syntax = impl_alias_ast.impl_path(db.upcast());
266
267    match resolver.resolve_generic_path_with_args(
268        &mut diagnostics,
269        &impl_path_syntax,
270        NotFoundItemType::Impl,
271        None,
272    ) {
273        Ok(ResolvedGenericItem::Impl(imp)) => Ok(imp),
274        Ok(ResolvedGenericItem::GenericImplAlias(impl_alias)) => db.impl_alias_impl_def(impl_alias),
275        // Skipping diagnostics since we will get these through when resolving in the
276        // `priv_impl_alias_semantic_data` query.
277        _ => Err(skip_diagnostic()),
278    }
279}
280
281/// Cycle handling for [crate::db::SemanticGroup::impl_alias_impl_def].
282pub fn impl_alias_impl_def_cycle(
283    _db: &dyn SemanticGroup,
284    _cycle: &salsa::Cycle,
285    _impl_alias_id: &ImplAliasId,
286) -> Maybe<ImplDefId> {
287    // Skipping diagnostics since we will get these through when resolving in the
288    // `priv_impl_alias_semantic_data` query.
289    Err(skip_diagnostic())
290}