cairo_lang_semantic/items/
structure.rs1use std::sync::Arc;
2
3use cairo_lang_defs::ids::{
4 LanguageElementId, LookupItemId, MemberId, MemberLongId, ModuleItemId, StructId,
5};
6use cairo_lang_diagnostics::{Diagnostics, Maybe, ToMaybe};
7use cairo_lang_proc_macros::{DebugWithDb, SemanticObject};
8use cairo_lang_syntax::attribute::structured::{Attribute, AttributeListStructurize};
9use cairo_lang_syntax::node::{Terminal, TypedStablePtr, TypedSyntaxNode};
10use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
11use cairo_lang_utils::{Intern, LookupIntern};
12use smol_str::SmolStr;
13
14use super::attribute::SemanticQueryAttrs;
15use super::feature_kind::extract_item_feature_config;
16use super::generics::{GenericParamsData, semantic_generic_params};
17use super::visibility::Visibility;
18use crate::db::SemanticGroup;
19use crate::diagnostic::SemanticDiagnosticKind::*;
20use crate::diagnostic::{SemanticDiagnostics, SemanticDiagnosticsBuilder};
21use crate::expr::inference::InferenceId;
22use crate::expr::inference::canonic::ResultNoErrEx;
23use crate::resolve::{Resolver, ResolverData};
24use crate::substitution::{GenericSubstitution, SemanticRewriter, SubstitutionRewriter};
25use crate::types::{ConcreteStructId, add_type_based_diagnostics, resolve_type};
26use crate::{GenericParam, SemanticDiagnostic, semantic};
27
28#[cfg(test)]
29#[path = "structure_test.rs"]
30mod test;
31
32#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
36#[debug_db(dyn SemanticGroup + 'static)]
37pub struct StructDeclarationData {
38 diagnostics: Diagnostics<SemanticDiagnostic>,
39 generic_params: Vec<semantic::GenericParam>,
40 attributes: Vec<Attribute>,
41 resolver_data: Arc<ResolverData>,
42}
43
44pub fn priv_struct_declaration_data(
46 db: &dyn SemanticGroup,
47 struct_id: StructId,
48) -> Maybe<StructDeclarationData> {
49 let mut diagnostics = SemanticDiagnostics::default();
50 let struct_ast = db.module_struct_by_id(struct_id)?.to_maybe()?;
55 let syntax_db = db.upcast();
56
57 let generic_params_data = db.struct_generic_params_data(struct_id)?;
59 let generic_params = generic_params_data.generic_params;
60 let inference_id = InferenceId::LookupItemDeclaration(LookupItemId::ModuleItem(
61 ModuleItemId::Struct(struct_id),
62 ));
63 let mut resolver = Resolver::with_data(
64 db,
65 (*generic_params_data.resolver_data).clone_with_inference_id(db, inference_id),
66 );
67 diagnostics.extend(generic_params_data.diagnostics);
68
69 let attributes = struct_ast.attributes(syntax_db).structurize(syntax_db);
70
71 let inference = &mut resolver.inference();
73 inference.finalize(&mut diagnostics, struct_ast.stable_ptr().untyped());
74
75 let generic_params = inference.rewrite(generic_params).no_err();
76 let resolver_data = Arc::new(resolver.data);
77 Ok(StructDeclarationData {
78 diagnostics: diagnostics.build(),
79 generic_params,
80 attributes,
81 resolver_data,
82 })
83}
84
85pub fn struct_declaration_diagnostics(
87 db: &dyn SemanticGroup,
88 struct_id: StructId,
89) -> Diagnostics<SemanticDiagnostic> {
90 db.priv_struct_declaration_data(struct_id).map(|data| data.diagnostics).unwrap_or_default()
91}
92
93pub fn struct_generic_params(
95 db: &dyn SemanticGroup,
96 struct_id: StructId,
97) -> Maybe<Vec<GenericParam>> {
98 db.struct_generic_params_data(struct_id).map(|data| data.generic_params)
99}
100
101pub fn struct_generic_params_data(
103 db: &dyn SemanticGroup,
104 struct_id: StructId,
105) -> Maybe<GenericParamsData> {
106 let module_file_id = struct_id.module_file_id(db.upcast());
107 let mut diagnostics = SemanticDiagnostics::default();
108 let struct_ast = db.module_struct_by_id(struct_id)?.to_maybe()?;
113 let inference_id =
115 InferenceId::LookupItemGenerics(LookupItemId::ModuleItem(ModuleItemId::Struct(struct_id)));
116 let mut resolver = Resolver::new(db, module_file_id, inference_id);
117 resolver.set_feature_config(&struct_id, &struct_ast, &mut diagnostics);
118 let generic_params = semantic_generic_params(
119 db,
120 &mut diagnostics,
121 &mut resolver,
122 module_file_id,
123 &struct_ast.generic_params(db.upcast()),
124 );
125 let inference = &mut resolver.inference();
126 inference.finalize(&mut diagnostics, struct_ast.stable_ptr().untyped());
127
128 let generic_params = inference.rewrite(generic_params).no_err();
129 let resolver_data = Arc::new(resolver.data);
130 Ok(GenericParamsData { generic_params, diagnostics: diagnostics.build(), resolver_data })
131}
132
133pub fn struct_attributes(db: &dyn SemanticGroup, struct_id: StructId) -> Maybe<Vec<Attribute>> {
135 Ok(db.priv_struct_declaration_data(struct_id)?.attributes)
136}
137
138pub fn struct_declaration_resolver_data(
140 db: &dyn SemanticGroup,
141 struct_id: StructId,
142) -> Maybe<Arc<ResolverData>> {
143 Ok(db.priv_struct_declaration_data(struct_id)?.resolver_data)
144}
145
146#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
148#[debug_db(dyn SemanticGroup + 'static)]
149pub struct StructDefinitionData {
150 diagnostics: Diagnostics<SemanticDiagnostic>,
151 members: Arc<OrderedHashMap<SmolStr, Member>>,
152 resolver_data: Arc<ResolverData>,
153}
154#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, SemanticObject)]
155#[debug_db(dyn SemanticGroup + 'static)]
156pub struct Member {
157 pub id: MemberId,
158 pub ty: semantic::TypeId,
159 #[dont_rewrite]
160 pub visibility: Visibility,
161}
162
163pub fn priv_struct_definition_data(
165 db: &dyn SemanticGroup,
166 struct_id: StructId,
167) -> Maybe<StructDefinitionData> {
168 let module_file_id = struct_id.module_file_id(db.upcast());
169 let mut diagnostics = SemanticDiagnostics::default();
170 let struct_ast = db.module_struct_by_id(struct_id)?.to_maybe()?;
175 let syntax_db = db.upcast();
176
177 let generic_params_data = db.struct_generic_params_data(struct_id)?;
179 let inference_id = InferenceId::LookupItemDefinition(LookupItemId::ModuleItem(
180 ModuleItemId::Struct(struct_id),
181 ));
182 let mut resolver = Resolver::with_data(
183 db,
184 (*generic_params_data.resolver_data).clone_with_inference_id(db, inference_id),
185 );
186 diagnostics.extend(generic_params_data.diagnostics);
187
188 let mut members = OrderedHashMap::default();
190 for member in struct_ast.members(syntax_db).elements(syntax_db) {
191 let feature_restore = resolver
192 .data
193 .feature_config
194 .override_with(extract_item_feature_config(db, &member, &mut diagnostics));
195 let id = MemberLongId(module_file_id, member.stable_ptr()).intern(db);
196 let ty = resolve_type(
197 db,
198 &mut diagnostics,
199 &mut resolver,
200 &member.type_clause(syntax_db).ty(syntax_db),
201 );
202 let visibility =
203 Visibility::from_ast(syntax_db, &mut diagnostics, &member.visibility(syntax_db));
204 let member_name = member.name(syntax_db).text(syntax_db);
205 if let Some(_other_member) =
206 members.insert(member_name.clone(), Member { id, ty, visibility })
207 {
208 diagnostics.report(&member, StructMemberRedefinition { struct_id, member_name });
209 }
210 resolver.data.feature_config.restore(feature_restore);
211 }
212
213 let inference = &mut resolver.inference();
215 inference.finalize(&mut diagnostics, struct_ast.stable_ptr().untyped());
216
217 for (_, member) in members.iter_mut() {
218 member.ty = inference.rewrite(member.ty).no_err();
219 }
220
221 let resolver_data = Arc::new(resolver.data);
222 Ok(StructDefinitionData {
223 diagnostics: diagnostics.build(),
224 members: members.into(),
225 resolver_data,
226 })
227}
228
229pub fn struct_definition_diagnostics(
231 db: &dyn SemanticGroup,
232 struct_id: StructId,
233) -> Diagnostics<SemanticDiagnostic> {
234 let Ok(data) = db.priv_struct_definition_data(struct_id) else {
235 return Default::default();
236 };
237 if db
240 .declared_phantom_type_attributes()
241 .iter()
242 .any(|attr| struct_id.has_attr(db, attr).unwrap_or_default())
243 {
244 return data.diagnostics;
245 }
246 let mut diagnostics = SemanticDiagnostics::from(data.diagnostics);
247 for (_, member) in data.members.iter() {
248 let stable_ptr = member.id.stable_ptr(db.upcast());
249 add_type_based_diagnostics(db, &mut diagnostics, member.ty, stable_ptr);
250 if member.ty.is_phantom(db) {
251 diagnostics.report(stable_ptr, NonPhantomTypeContainingPhantomType);
252 }
253 }
254 diagnostics.build()
255}
256
257pub fn struct_members(
259 db: &dyn SemanticGroup,
260 struct_id: StructId,
261) -> Maybe<Arc<OrderedHashMap<SmolStr, Member>>> {
262 Ok(db.priv_struct_definition_data(struct_id)?.members)
263}
264
265pub fn struct_definition_resolver_data(
267 db: &dyn SemanticGroup,
268 struct_id: StructId,
269) -> Maybe<Arc<ResolverData>> {
270 Ok(db.priv_struct_definition_data(struct_id)?.resolver_data)
271}
272
273pub fn concrete_struct_members(
275 db: &dyn SemanticGroup,
276 concrete_struct_id: ConcreteStructId,
277) -> Maybe<Arc<OrderedHashMap<SmolStr, semantic::Member>>> {
278 let generic_params = db.struct_generic_params(concrete_struct_id.struct_id(db))?;
281 let generic_args = concrete_struct_id.lookup_intern(db).generic_args;
282 let substitution = GenericSubstitution::new(&generic_params, &generic_args);
283
284 let generic_members = db.struct_members(concrete_struct_id.struct_id(db))?;
285 Ok(Arc::new(
286 generic_members
287 .iter()
288 .map(|(name, member)| {
289 let ty =
290 SubstitutionRewriter { db, substitution: &substitution }.rewrite(member.ty)?;
291 Ok((name.clone(), semantic::Member { ty, ..member.clone() }))
292 })
293 .collect::<Maybe<_>>()?,
294 ))
295}