cairo_lang_semantic/items/
free_function.rs

1use 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
33// === Declaration ===
34
35// --- Selectors ---
36
37/// Query implementation of [crate::db::SemanticGroup::free_function_declaration_diagnostics].
38pub 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
47/// Query implementation of [crate::db::SemanticGroup::free_function_signature].
48pub 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
55/// Query implementation of [crate::db::SemanticGroup::free_function_declaration_implicits].
56pub 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
63/// Query implementation of [SemanticGroup::free_function_declaration_implicit_precedence]
64pub 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
71/// Query implementation of [crate::db::SemanticGroup::free_function_generic_params].
72pub 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
79/// Query implementation of [crate::db::SemanticGroup::free_function_generic_params_data].
80pub 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    // Generic params.
91    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
112/// Query implementation of [crate::db::SemanticGroup::free_function_declaration_resolver_data].
113pub 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
120/// Query implementation of [crate::db::SemanticGroup::free_function_declaration_inline_config].
121pub 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
128// --- Computation ---
129
130/// Query implementation of [crate::db::SemanticGroup::priv_free_function_declaration_data].
131pub 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    // Generic params.
141    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_syntax = declaration.signature(syntax_db);
154    let signature = semantic::Signature::from_ast(
155        &mut diagnostics,
156        db,
157        &mut resolver,
158        &signature_syntax,
159        FunctionTitleId::Free(free_function_id),
160        &mut environment,
161    );
162
163    let attributes = free_function_syntax.attributes(syntax_db).structurize(syntax_db);
164
165    let inline_config = get_inline_config(db, &mut diagnostics, &attributes)?;
166
167    forbid_inline_always_with_impl_generic_param(&mut diagnostics, &generic_params, &inline_config);
168
169    let (implicit_precedence, _) =
170        get_implicit_precedence(&mut diagnostics, &mut resolver, &attributes);
171
172    // Check fully resolved.
173    let inference = &mut resolver.inference();
174
175    inference.finalize(&mut diagnostics, declaration.stable_ptr().untyped());
176    let signature = inference.rewrite(signature).no_err();
177    let generic_params = inference.rewrite(generic_params).no_err();
178
179    Ok(FunctionDeclarationData {
180        diagnostics: diagnostics.build(),
181        signature,
182        environment,
183        generic_params,
184        attributes,
185        resolver_data: Arc::new(resolver.data),
186        inline_config,
187        implicit_precedence,
188    })
189}
190
191// === Body ===
192
193// --- Selectors ---
194
195/// Query implementation of [crate::db::SemanticGroup::free_function_body_diagnostics].
196pub fn free_function_body_diagnostics(
197    db: &dyn SemanticGroup,
198    free_function_id: FreeFunctionId,
199) -> Diagnostics<SemanticDiagnostic> {
200    db.priv_free_function_body_data(free_function_id)
201        .map(|data| data.diagnostics)
202        .unwrap_or_default()
203}
204
205/// Query implementation of [crate::db::SemanticGroup::free_function_body_resolver_data].
206pub fn free_function_body_resolver_data(
207    db: &dyn SemanticGroup,
208    free_function_id: FreeFunctionId,
209) -> Maybe<Arc<ResolverData>> {
210    Ok(db.priv_free_function_body_data(free_function_id)?.resolver_data)
211}
212
213// --- Computation ---
214
215/// Query implementation of [crate::db::SemanticGroup::priv_free_function_body_data].
216pub fn priv_free_function_body_data(
217    db: &dyn SemanticGroup,
218    free_function_id: FreeFunctionId,
219) -> Maybe<FunctionBodyData> {
220    let mut diagnostics = SemanticDiagnostics::default();
221    let free_function_syntax = db.module_free_function_by_id(free_function_id)?.to_maybe()?;
222    // Compute declaration semantic.
223    let declaration = db.priv_free_function_declaration_data(free_function_id)?;
224
225    // Generic params.
226    let parent_resolver_data = db.free_function_declaration_resolver_data(free_function_id)?;
227    let inference_id = InferenceId::LookupItemDefinition(LookupItemId::ModuleItem(
228        ModuleItemId::FreeFunction(free_function_id),
229    ));
230    let resolver =
231        Resolver::with_data(db, (*parent_resolver_data).clone_with_inference_id(db, inference_id));
232
233    let environment = declaration.environment;
234    let function_id = (|| {
235        let generic_function = GenericFunctionId::Free(free_function_id);
236
237        Ok(FunctionLongId::from_generic(db, generic_function)?.intern(db))
238    })();
239    // Compute body semantic expr.
240    let mut ctx = ComputationContext::new(
241        db,
242        &mut diagnostics,
243        resolver,
244        Some(&declaration.signature),
245        environment,
246        ContextFunction::Function(function_id),
247    );
248    let function_body = free_function_syntax.body(db.upcast());
249    let return_type = declaration.signature.return_type;
250    let body_expr = compute_root_expr(&mut ctx, &function_body, return_type)?;
251    let ComputationContext { arenas: Arenas { exprs, patterns, statements }, resolver, .. } = ctx;
252
253    let expr_lookup: UnorderedHashMap<_, _> =
254        exprs.iter().map(|(expr_id, expr)| (expr.stable_ptr(), expr_id)).collect();
255    let pattern_lookup: UnorderedHashMap<_, _> =
256        patterns.iter().map(|(pattern_id, pattern)| (pattern.stable_ptr(), pattern_id)).collect();
257    let resolver_data = Arc::new(resolver.data);
258    Ok(FunctionBodyData {
259        diagnostics: diagnostics.build(),
260        expr_lookup,
261        pattern_lookup,
262        resolver_data,
263        body: Arc::new(FunctionBody { arenas: Arenas { exprs, patterns, statements }, body_expr }),
264    })
265}