Skip to main content

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