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::default();
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 impl_alias_id: ImplAliasId<'db>,
106 _in_cycle: bool,
107) -> Maybe<ImplAliasData<'db>> {
108 impl_alias_semantic_data(db, impl_alias_id, true).clone()
109}
110
111pub fn impl_alias_semantic_data_cycle_helper<'db>(
113 db: &'db dyn Database,
114 impl_alias_ast: &ast::ItemImplAlias<'db>,
115 lookup_item_id: LookupItemId<'db>,
116 generic_params_data: GenericParamsData<'db>,
117) -> Maybe<ImplAliasData<'db>> {
118 let mut diagnostics = SemanticDiagnostics::default();
119 let err = Err(diagnostics.report(impl_alias_ast.name(db).stable_ptr(db), ImplAliasCycle));
124 diagnostics.extend(generic_params_data.diagnostics);
125 let inference_id = InferenceId::LookupItemDeclaration(lookup_item_id);
126 let attributes = impl_alias_ast.attributes(db).structurize(db);
127 Ok(ImplAliasData {
128 diagnostics: diagnostics.build(),
129 resolved_impl: err,
130 attributes,
131 resolver_data: (*generic_params_data.resolver_data)
132 .clone_with_inference_id(db, inference_id)
133 .into(),
134 })
135}
136
137#[salsa::tracked(returns(ref))]
139fn impl_alias_generic_params_data<'db>(
140 db: &'db dyn Database,
141 impl_alias_id: ImplAliasId<'db>,
142) -> Maybe<GenericParamsData<'db>> {
143 let module_id = impl_alias_id.module_id(db);
144 let impl_alias_ast = db.module_impl_alias_by_id(impl_alias_id)?;
145 impl_alias_generic_params_data_helper(
146 db,
147 module_id,
148 &impl_alias_ast,
149 LookupItemId::ModuleItem(ModuleItemId::ImplAlias(impl_alias_id)),
150 None,
151 )
152}
153
154pub fn impl_alias_generic_params_data_helper<'db>(
156 db: &'db dyn Database,
157 module_id: ModuleId<'db>,
158 impl_alias_ast: &ast::ItemImplAlias<'db>,
159 lookup_item_id: LookupItemId<'db>,
160 parent_resolver_data: Option<Arc<ResolverData<'db>>>,
161) -> Maybe<GenericParamsData<'db>> {
162 let mut diagnostics = SemanticDiagnostics::default();
163 let inference_id = InferenceId::LookupItemGenerics(lookup_item_id);
164
165 let mut resolver = match parent_resolver_data {
166 Some(parent_resolver_data) => {
167 Resolver::with_data(db, parent_resolver_data.clone_with_inference_id(db, inference_id))
168 }
169 None => Resolver::new(db, module_id, inference_id),
170 };
171 resolver.set_feature_config(&lookup_item_id, impl_alias_ast, &mut diagnostics);
172 let generic_params = semantic_generic_params(
173 db,
174 &mut diagnostics,
175 &mut resolver,
176 module_id,
177 &impl_alias_ast.generic_params(db),
178 );
179
180 let inference = &mut resolver.inference();
181 inference.finalize(&mut diagnostics, impl_alias_ast.stable_ptr(db).untyped());
182
183 let generic_params = inference.rewrite(generic_params).no_err();
184 let resolver_data = Arc::new(resolver.data);
185 Ok(GenericParamsData { diagnostics: diagnostics.build(), generic_params, resolver_data })
186}
187
188#[salsa::tracked(cycle_result=impl_alias_impl_def_cycle)]
190fn impl_alias_impl_def<'db>(
191 db: &'db dyn Database,
192 impl_alias_id: ImplAliasId<'db>,
193) -> Maybe<ImplDefId<'db>> {
194 let module_id = impl_alias_id.module_id(db);
195 let mut diagnostics = SemanticDiagnostics::default();
196 let impl_alias_ast = db.module_impl_alias_by_id(impl_alias_id)?;
197 let inference_id = InferenceId::ImplAliasImplDef(impl_alias_id);
198
199 let mut resolver = Resolver::new(db, module_id, inference_id);
200 resolver.set_feature_config(&impl_alias_id, &impl_alias_ast, &mut diagnostics);
201
202 let impl_path_syntax = impl_alias_ast.impl_path(db);
203
204 match resolver.resolve_generic_path_with_args(
205 &mut diagnostics,
206 &impl_path_syntax,
207 NotFoundItemType::Impl,
208 ResolutionContext::Default,
209 ) {
210 Ok(ResolvedGenericItem::Impl(imp)) => Ok(imp),
211 Ok(ResolvedGenericItem::GenericImplAlias(impl_alias)) => db.impl_alias_impl_def(impl_alias),
212 _ => Err(skip_diagnostic()),
215 }
216}
217
218fn impl_alias_impl_def_cycle<'db>(
220 _db: &dyn Database,
221 _impl_alias_id: ImplAliasId<'db>,
222) -> Maybe<ImplDefId<'db>> {
223 Err(skip_diagnostic())
226}
227
228pub trait ImplAliasSemantic<'db>: Database {
230 fn impl_alias_impl_def(&'db self, id: ImplAliasId<'db>) -> Maybe<ImplDefId<'db>> {
233 impl_alias_impl_def(self.as_dyn_database(), id)
234 }
235 fn impl_alias_semantic_diagnostics(
237 &'db self,
238 id: ImplAliasId<'db>,
239 ) -> Diagnostics<'db, SemanticDiagnostic<'db>> {
240 impl_alias_semantic_data(self.as_dyn_database(), id, false)
241 .as_ref()
242 .map(|data| data.diagnostics.clone())
243 .unwrap_or_default()
244 }
245 fn impl_alias_resolved_impl(&'db self, id: ImplAliasId<'db>) -> Maybe<ImplId<'db>> {
247 let db = self.as_dyn_database();
248 if let Some(data) = db.cached_crate_semantic_data(id.module_id(db).owning_crate(db)) {
249 if let Some(resolved_impl) = data.impl_aliases_resolved_impls.get(&id) {
250 return Ok(*resolved_impl);
251 } else {
252 panic!(
253 "impl alias not found in cached impl_aliases_resolved_impls {:?}",
254 id.debug(db)
255 );
256 }
257 };
258 impl_alias_semantic_data(self.as_dyn_database(), id, false).maybe_as_ref()?.resolved_impl
259 }
260 fn impl_alias_generic_params(&'db self, id: ImplAliasId<'db>) -> Maybe<Vec<GenericParam<'db>>> {
262 Ok(impl_alias_generic_params_data(self.as_dyn_database(), id)
263 .maybe_as_ref()?
264 .generic_params
265 .clone())
266 }
267 fn impl_alias_resolver_data(&'db self, id: ImplAliasId<'db>) -> Maybe<Arc<ResolverData<'db>>> {
269 Ok(impl_alias_semantic_data(self.as_dyn_database(), id, false)
270 .maybe_as_ref()?
271 .resolver_data
272 .clone())
273 }
274 fn impl_alias_attributes(&'db self, id: ImplAliasId<'db>) -> Maybe<&'db [Attribute<'db>]> {
276 Ok(&impl_alias_semantic_data(self.as_dyn_database(), id, false).maybe_as_ref()?.attributes)
277 }
278}
279impl<'db, T: Database + ?Sized> ImplAliasSemantic<'db> for T {}