cairo_lang_semantic/items/
impl_alias.rs1use std::sync::Arc;
2
3use cairo_lang_debug::DebugWithDb;
4use cairo_lang_defs::db::DefsGroup;
5use cairo_lang_defs::ids::{
6 ImplAliasId, ImplDefId, LanguageElementId, LookupItemId, ModuleId, ModuleItemId,
7};
8use cairo_lang_diagnostics::{Diagnostics, Maybe, MaybeAsRef, skip_diagnostic};
9use cairo_lang_proc_macros::DebugWithDb;
10use cairo_lang_syntax::attribute::structured::{Attribute, AttributeListStructurize};
11use cairo_lang_syntax::node::{TypedStablePtr, TypedSyntaxNode, ast};
12use cairo_lang_utils::try_extract_matches;
13use salsa::Database;
14
15use super::generics::{GenericParamsData, semantic_generic_params};
16use super::imp::ImplId;
17use crate::db::SemanticGroup;
18use crate::diagnostic::SemanticDiagnosticKind::*;
19use crate::diagnostic::{NotFoundItemType, SemanticDiagnostics, SemanticDiagnosticsBuilder};
20use crate::expr::inference::InferenceId;
21use crate::expr::inference::canonic::ResultNoErrEx;
22use crate::resolve::{
23 ResolutionContext, ResolvedConcreteItem, ResolvedGenericItem, Resolver, ResolverData,
24};
25use crate::substitution::SemanticRewriter;
26use crate::{GenericParam, SemanticDiagnostic};
27
28#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, salsa::Update)]
29#[debug_db(dyn Database)]
30pub struct ImplAliasData<'db> {
31 pub diagnostics: Diagnostics<'db, SemanticDiagnostic<'db>>,
32 pub resolved_impl: Maybe<ImplId<'db>>,
33 attributes: Vec<Attribute<'db>>,
34 pub resolver_data: Arc<ResolverData<'db>>,
35}
36
37#[salsa::tracked(cycle_result=impl_alias_semantic_data_cycle, returns(ref))]
39fn impl_alias_semantic_data<'db>(
40 db: &'db dyn Database,
41 impl_alias_id: ImplAliasId<'db>,
42 in_cycle: bool,
43) -> Maybe<ImplAliasData<'db>> {
44 let lookup_item_id = LookupItemId::ModuleItem(ModuleItemId::ImplAlias(impl_alias_id));
45 let impl_alias_ast = db.module_impl_alias_by_id(impl_alias_id)?;
46
47 let generic_params_data =
48 impl_alias_generic_params_data(db, impl_alias_id).maybe_as_ref()?.clone();
49
50 if in_cycle {
51 impl_alias_semantic_data_cycle_helper(
52 db,
53 &impl_alias_ast,
54 lookup_item_id,
55 generic_params_data,
56 )
57 } else {
58 impl_alias_semantic_data_helper(db, &impl_alias_ast, lookup_item_id, generic_params_data)
59 }
60}
61
62pub fn impl_alias_semantic_data_helper<'db>(
64 db: &'db dyn Database,
65 impl_alias_ast: &ast::ItemImplAlias<'db>,
66 lookup_item_id: LookupItemId<'db>,
67 generic_params_data: GenericParamsData<'db>,
68) -> Maybe<ImplAliasData<'db>> {
69 let mut diagnostics = SemanticDiagnostics::new(lookup_item_id.parent_module(db));
70 let inference_id = InferenceId::LookupItemDeclaration(lookup_item_id);
75 let mut resolver = Resolver::with_data(
76 db,
77 (*generic_params_data.resolver_data).clone_with_inference_id(db, inference_id),
78 );
79 diagnostics.extend(generic_params_data.diagnostics);
80
81 let item = resolver.resolve_concrete_path(
82 &mut diagnostics,
83 &impl_alias_ast.impl_path(db),
84 NotFoundItemType::Impl,
85 );
86 let resolved_impl = item.and_then(|item| {
87 try_extract_matches!(item, ResolvedConcreteItem::Impl).ok_or_else(|| {
88 diagnostics.report(impl_alias_ast.impl_path(db).stable_ptr(db), UnknownImpl)
89 })
90 });
91
92 let inference = &mut resolver.inference();
94 inference.finalize(&mut diagnostics, impl_alias_ast.stable_ptr(db).untyped());
95
96 let resolved_impl = inference.rewrite(resolved_impl).no_err();
97
98 let attributes = impl_alias_ast.attributes(db).structurize(db);
99 let resolver_data = Arc::new(resolver.data);
100 Ok(ImplAliasData { diagnostics: diagnostics.build(), resolved_impl, attributes, resolver_data })
101}
102
103fn impl_alias_semantic_data_cycle<'db>(
104 db: &'db dyn Database,
105 _id: salsa::Id,
106 impl_alias_id: ImplAliasId<'db>,
107 _in_cycle: bool,
108) -> Maybe<ImplAliasData<'db>> {
109 impl_alias_semantic_data(db, impl_alias_id, true).clone()
110}
111
112pub fn impl_alias_semantic_data_cycle_helper<'db>(
114 db: &'db dyn Database,
115 impl_alias_ast: &ast::ItemImplAlias<'db>,
116 lookup_item_id: LookupItemId<'db>,
117 generic_params_data: GenericParamsData<'db>,
118) -> Maybe<ImplAliasData<'db>> {
119 let mut diagnostics = SemanticDiagnostics::new(lookup_item_id.parent_module(db));
120 let err = Err(diagnostics.report(impl_alias_ast.name(db).stable_ptr(db), ImplAliasCycle));
125 diagnostics.extend(generic_params_data.diagnostics);
126 let inference_id = InferenceId::LookupItemDeclaration(lookup_item_id);
127 let attributes = impl_alias_ast.attributes(db).structurize(db);
128 Ok(ImplAliasData {
129 diagnostics: diagnostics.build(),
130 resolved_impl: err,
131 attributes,
132 resolver_data: (*generic_params_data.resolver_data)
133 .clone_with_inference_id(db, inference_id)
134 .into(),
135 })
136}
137
138#[salsa::tracked(returns(ref))]
140fn impl_alias_generic_params_data<'db>(
141 db: &'db dyn Database,
142 impl_alias_id: ImplAliasId<'db>,
143) -> Maybe<GenericParamsData<'db>> {
144 let module_id = impl_alias_id.parent_module(db);
145 let impl_alias_ast = db.module_impl_alias_by_id(impl_alias_id)?;
146 impl_alias_generic_params_data_helper(
147 db,
148 module_id,
149 &impl_alias_ast,
150 LookupItemId::ModuleItem(ModuleItemId::ImplAlias(impl_alias_id)),
151 None,
152 )
153}
154
155pub fn impl_alias_generic_params_data_helper<'db>(
157 db: &'db dyn Database,
158 module_id: ModuleId<'db>,
159 impl_alias_ast: &ast::ItemImplAlias<'db>,
160 lookup_item_id: LookupItemId<'db>,
161 parent_resolver_data: Option<Arc<ResolverData<'db>>>,
162) -> Maybe<GenericParamsData<'db>> {
163 let mut diagnostics = SemanticDiagnostics::new(module_id);
164 let inference_id = InferenceId::LookupItemGenerics(lookup_item_id);
165
166 let mut resolver = match parent_resolver_data {
167 Some(parent_resolver_data) => {
168 Resolver::with_data(db, parent_resolver_data.clone_with_inference_id(db, inference_id))
169 }
170 None => Resolver::new(db, module_id, inference_id),
171 };
172 resolver.set_feature_config(&lookup_item_id, impl_alias_ast, &mut diagnostics);
173 let generic_params = semantic_generic_params(
174 db,
175 &mut diagnostics,
176 &mut resolver,
177 module_id,
178 &impl_alias_ast.generic_params(db),
179 );
180
181 let inference = &mut resolver.inference();
182 inference.finalize(&mut diagnostics, impl_alias_ast.stable_ptr(db).untyped());
183
184 let generic_params = inference.rewrite(generic_params).no_err();
185 let resolver_data = Arc::new(resolver.data);
186 Ok(GenericParamsData { diagnostics: diagnostics.build(), generic_params, resolver_data })
187}
188
189#[salsa::tracked(cycle_result=impl_alias_impl_def_cycle)]
191fn impl_alias_impl_def<'db>(
192 db: &'db dyn Database,
193 impl_alias_id: ImplAliasId<'db>,
194) -> Maybe<ImplDefId<'db>> {
195 let module_id = impl_alias_id.parent_module(db);
196 let mut diagnostics = SemanticDiagnostics::new(module_id);
197 let impl_alias_ast = db.module_impl_alias_by_id(impl_alias_id)?;
198 let inference_id = InferenceId::ImplAliasImplDef(impl_alias_id);
199
200 let mut resolver = Resolver::new(db, module_id, inference_id);
201 resolver.set_feature_config(&impl_alias_id, &impl_alias_ast, &mut diagnostics);
202
203 let impl_path_syntax = impl_alias_ast.impl_path(db);
204
205 match resolver.resolve_generic_path_with_args(
206 &mut diagnostics,
207 &impl_path_syntax,
208 NotFoundItemType::Impl,
209 ResolutionContext::Default,
210 ) {
211 Ok(ResolvedGenericItem::Impl(imp)) => Ok(imp),
212 Ok(ResolvedGenericItem::GenericImplAlias(impl_alias)) => db.impl_alias_impl_def(impl_alias),
213 _ => Err(skip_diagnostic()),
216 }
217}
218
219fn impl_alias_impl_def_cycle<'db>(
221 _db: &dyn Database,
222 _id: salsa::Id,
223 _impl_alias_id: ImplAliasId<'db>,
224) -> Maybe<ImplDefId<'db>> {
225 Err(skip_diagnostic())
228}
229
230pub trait ImplAliasSemantic<'db>: Database {
232 fn impl_alias_impl_def(&'db self, id: ImplAliasId<'db>) -> Maybe<ImplDefId<'db>> {
235 impl_alias_impl_def(self.as_dyn_database(), id)
236 }
237 fn impl_alias_semantic_diagnostics(
239 &'db self,
240 id: ImplAliasId<'db>,
241 ) -> Diagnostics<'db, SemanticDiagnostic<'db>> {
242 impl_alias_semantic_data(self.as_dyn_database(), id, false)
243 .as_ref()
244 .map(|data| data.diagnostics.clone())
245 .unwrap_or_default()
246 }
247 fn impl_alias_resolved_impl(&'db self, id: ImplAliasId<'db>) -> Maybe<ImplId<'db>> {
249 let db = self.as_dyn_database();
250 if let Some(data) = db.cached_crate_semantic_data(id.parent_module(db).owning_crate(db)) {
251 if let Some(resolved_impl) = data.impl_aliases_resolved_impls.get(&id) {
252 return Ok(*resolved_impl);
253 } else {
254 panic!(
255 "impl alias not found in cached impl_aliases_resolved_impls {:?}",
256 id.debug(db)
257 );
258 }
259 };
260 impl_alias_semantic_data(self.as_dyn_database(), id, false).maybe_as_ref()?.resolved_impl
261 }
262 fn impl_alias_generic_params(&'db self, id: ImplAliasId<'db>) -> Maybe<Vec<GenericParam<'db>>> {
264 Ok(impl_alias_generic_params_data(self.as_dyn_database(), id)
265 .maybe_as_ref()?
266 .generic_params
267 .clone())
268 }
269 fn impl_alias_resolver_data(&'db self, id: ImplAliasId<'db>) -> Maybe<Arc<ResolverData<'db>>> {
271 Ok(impl_alias_semantic_data(self.as_dyn_database(), id, false)
272 .maybe_as_ref()?
273 .resolver_data
274 .clone())
275 }
276 fn impl_alias_attributes(&'db self, id: ImplAliasId<'db>) -> Maybe<&'db [Attribute<'db>]> {
278 Ok(&impl_alias_semantic_data(self.as_dyn_database(), id, false).maybe_as_ref()?.attributes)
279 }
280}
281impl<'db, T: Database + ?Sized> ImplAliasSemantic<'db> for T {}