cairo_lang_semantic/items/
free_function.rs1use std::sync::Arc;
2
3use cairo_lang_defs::ids::{
4 FreeFunctionId, FunctionTitleId, LanguageElementId, LookupItemId, ModuleItemId,
5};
6use cairo_lang_diagnostics::{Diagnostics, Maybe, ToMaybe};
7use cairo_lang_syntax::attribute::structured::AttributeListStructurize;
8use cairo_lang_syntax::node::{TypedStablePtr, TypedSyntaxNode};
9use cairo_lang_utils::Intern;
10use cairo_lang_utils::unordered_hash_map::UnorderedHashMap;
11
12use super::function_with_body::{FunctionBody, FunctionBodyData, get_inline_config};
13use super::functions::{
14 FunctionDeclarationData, GenericFunctionId, InlineConfiguration,
15 forbid_inline_always_with_impl_generic_param,
16};
17use super::generics::{GenericParamsData, semantic_generic_params};
18use crate::db::SemanticGroup;
19use crate::diagnostic::SemanticDiagnostics;
20use crate::expr::compute::{ComputationContext, ContextFunction, Environment, compute_root_expr};
21use crate::expr::inference::InferenceId;
22use crate::expr::inference::canonic::ResultNoErrEx;
23use crate::items::function_with_body::get_implicit_precedence;
24use crate::items::functions::ImplicitPrecedence;
25use crate::resolve::{Resolver, ResolverData};
26use crate::substitution::SemanticRewriter;
27use crate::{Arenas, FunctionLongId, SemanticDiagnostic, TypeId, semantic};
28
29#[cfg(test)]
30#[path = "free_function_test.rs"]
31mod test;
32
33pub fn free_function_declaration_diagnostics(
39 db: &dyn SemanticGroup,
40 free_function_id: FreeFunctionId,
41) -> Diagnostics<SemanticDiagnostic> {
42 db.priv_free_function_declaration_data(free_function_id)
43 .map(|data| data.diagnostics)
44 .unwrap_or_default()
45}
46
47pub fn free_function_signature(
49 db: &dyn SemanticGroup,
50 free_function_id: FreeFunctionId,
51) -> Maybe<semantic::Signature> {
52 Ok(db.priv_free_function_declaration_data(free_function_id)?.signature)
53}
54
55pub fn free_function_declaration_implicits(
57 db: &dyn SemanticGroup,
58 free_function_id: FreeFunctionId,
59) -> Maybe<Vec<TypeId>> {
60 Ok(db.priv_free_function_declaration_data(free_function_id)?.signature.implicits)
61}
62
63pub fn free_function_declaration_implicit_precedence(
65 db: &dyn SemanticGroup,
66 free_function_id: FreeFunctionId,
67) -> Maybe<ImplicitPrecedence> {
68 Ok(db.priv_free_function_declaration_data(free_function_id)?.implicit_precedence)
69}
70
71pub fn free_function_generic_params(
73 db: &dyn SemanticGroup,
74 free_function_id: FreeFunctionId,
75) -> Maybe<Vec<semantic::GenericParam>> {
76 Ok(db.free_function_generic_params_data(free_function_id)?.generic_params)
77}
78
79pub fn free_function_generic_params_data(
81 db: &dyn SemanticGroup,
82 free_function_id: FreeFunctionId,
83) -> Maybe<GenericParamsData> {
84 let syntax_db = db.upcast();
85 let module_file_id = free_function_id.module_file_id(db.upcast());
86 let mut diagnostics = SemanticDiagnostics::default();
87 let free_function_syntax = db.module_free_function_by_id(free_function_id)?.to_maybe()?;
88 let declaration = free_function_syntax.declaration(syntax_db);
89
90 let inference_id = InferenceId::LookupItemGenerics(LookupItemId::ModuleItem(
92 ModuleItemId::FreeFunction(free_function_id),
93 ));
94 let mut resolver = Resolver::new(db, module_file_id, inference_id);
95 resolver.set_feature_config(&free_function_id, &free_function_syntax, &mut diagnostics);
96 let generic_params = semantic_generic_params(
97 db,
98 &mut diagnostics,
99 &mut resolver,
100 module_file_id,
101 &declaration.generic_params(syntax_db),
102 );
103
104 let inference = &mut resolver.inference();
105 inference.finalize(&mut diagnostics, free_function_syntax.stable_ptr().untyped());
106
107 let generic_params = inference.rewrite(generic_params).no_err();
108 let resolver_data = Arc::new(resolver.data);
109 Ok(GenericParamsData { diagnostics: diagnostics.build(), generic_params, resolver_data })
110}
111
112pub fn free_function_declaration_resolver_data(
114 db: &dyn SemanticGroup,
115 free_function_id: FreeFunctionId,
116) -> Maybe<Arc<ResolverData>> {
117 Ok(db.priv_free_function_declaration_data(free_function_id)?.resolver_data)
118}
119
120pub fn free_function_declaration_inline_config(
122 db: &dyn SemanticGroup,
123 free_function_id: FreeFunctionId,
124) -> Maybe<InlineConfiguration> {
125 Ok(db.priv_free_function_declaration_data(free_function_id)?.inline_config)
126}
127
128pub fn priv_free_function_declaration_data(
132 db: &dyn SemanticGroup,
133 free_function_id: FreeFunctionId,
134) -> Maybe<FunctionDeclarationData> {
135 let syntax_db = db.upcast();
136 let mut diagnostics = SemanticDiagnostics::default();
137 let free_function_syntax = db.module_free_function_by_id(free_function_id)?.to_maybe()?;
138 let declaration = free_function_syntax.declaration(syntax_db);
139
140 let generic_params_data = db.free_function_generic_params_data(free_function_id)?;
142 let generic_params = generic_params_data.generic_params;
143 let lookup_item_id = LookupItemId::ModuleItem(ModuleItemId::FreeFunction(free_function_id));
144 let inference_id = InferenceId::LookupItemDeclaration(lookup_item_id);
145 let mut resolver = Resolver::with_data(
146 db,
147 (*generic_params_data.resolver_data).clone_with_inference_id(db, inference_id),
148 );
149 diagnostics.extend(generic_params_data.diagnostics);
150
151 let mut environment = Environment::empty();
152
153 let signature = semantic::Signature::from_ast(
154 &mut diagnostics,
155 db,
156 &mut resolver,
157 &declaration,
158 FunctionTitleId::Free(free_function_id),
159 &mut environment,
160 );
161
162 let attributes = free_function_syntax.attributes(syntax_db).structurize(syntax_db);
163
164 let inline_config = get_inline_config(db, &mut diagnostics, &attributes)?;
165
166 forbid_inline_always_with_impl_generic_param(&mut diagnostics, &generic_params, &inline_config);
167
168 let (implicit_precedence, _) =
169 get_implicit_precedence(&mut diagnostics, &mut resolver, &attributes);
170
171 let inference = &mut resolver.inference();
173
174 inference.finalize(&mut diagnostics, declaration.stable_ptr().untyped());
175 let signature = inference.rewrite(signature).no_err();
176 let generic_params = inference.rewrite(generic_params).no_err();
177
178 Ok(FunctionDeclarationData {
179 diagnostics: diagnostics.build(),
180 signature,
181 environment,
182 generic_params,
183 attributes,
184 resolver_data: Arc::new(resolver.data),
185 inline_config,
186 implicit_precedence,
187 })
188}
189
190pub fn free_function_body_diagnostics(
196 db: &dyn SemanticGroup,
197 free_function_id: FreeFunctionId,
198) -> Diagnostics<SemanticDiagnostic> {
199 db.priv_free_function_body_data(free_function_id)
200 .map(|data| data.diagnostics)
201 .unwrap_or_default()
202}
203
204pub fn free_function_body_resolver_data(
206 db: &dyn SemanticGroup,
207 free_function_id: FreeFunctionId,
208) -> Maybe<Arc<ResolverData>> {
209 Ok(db.priv_free_function_body_data(free_function_id)?.resolver_data)
210}
211
212pub fn priv_free_function_body_data(
216 db: &dyn SemanticGroup,
217 free_function_id: FreeFunctionId,
218) -> Maybe<FunctionBodyData> {
219 let mut diagnostics = SemanticDiagnostics::default();
220 let free_function_syntax = db.module_free_function_by_id(free_function_id)?.to_maybe()?;
221 let declaration = db.priv_free_function_declaration_data(free_function_id)?;
223
224 let parent_resolver_data = db.free_function_declaration_resolver_data(free_function_id)?;
226 let inference_id = InferenceId::LookupItemDefinition(LookupItemId::ModuleItem(
227 ModuleItemId::FreeFunction(free_function_id),
228 ));
229 let resolver =
230 Resolver::with_data(db, (*parent_resolver_data).clone_with_inference_id(db, inference_id));
231
232 let environment = declaration.environment;
233 let function_id = (|| {
234 let generic_function = GenericFunctionId::Free(free_function_id);
235
236 Ok(FunctionLongId::from_generic(db, generic_function)?.intern(db))
237 })();
238 let mut ctx = ComputationContext::new(
240 db,
241 &mut diagnostics,
242 resolver,
243 Some(&declaration.signature),
244 environment,
245 ContextFunction::Function(function_id),
246 );
247 let function_body = free_function_syntax.body(db.upcast());
248 let return_type = declaration.signature.return_type;
249 let body_expr = compute_root_expr(&mut ctx, &function_body, return_type)?;
250 let ComputationContext { arenas: Arenas { exprs, patterns, statements }, resolver, .. } = ctx;
251
252 let expr_lookup: UnorderedHashMap<_, _> =
253 exprs.iter().map(|(expr_id, expr)| (expr.stable_ptr(), expr_id)).collect();
254 let pattern_lookup: UnorderedHashMap<_, _> =
255 patterns.iter().map(|(pattern_id, pattern)| (pattern.stable_ptr(), pattern_id)).collect();
256 let resolver_data = Arc::new(resolver.data);
257 Ok(FunctionBodyData {
258 diagnostics: diagnostics.build(),
259 expr_lookup,
260 pattern_lookup,
261 resolver_data,
262 body: Arc::new(FunctionBody { arenas: Arenas { exprs, patterns, statements }, body_expr }),
263 })
264}