cairo_lang_semantic/items/
extern_function.rs

1use std::sync::Arc;
2
3use cairo_lang_defs::ids::{
4    ExternFunctionId, 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::extract_matches;
10
11use super::function_with_body::get_inline_config;
12use super::functions::{FunctionDeclarationData, GenericFunctionId, InlineConfiguration};
13use super::generics::{GenericParamsData, semantic_generic_params};
14use crate::corelib::get_core_generic_function_id;
15use crate::db::SemanticGroup;
16use crate::diagnostic::SemanticDiagnosticKind::*;
17use crate::diagnostic::{SemanticDiagnostics, SemanticDiagnosticsBuilder};
18use crate::expr::compute::Environment;
19use crate::expr::inference::InferenceId;
20use crate::expr::inference::canonic::ResultNoErrEx;
21use crate::items::function_with_body::get_implicit_precedence;
22use crate::items::functions::ImplicitPrecedence;
23use crate::resolve::{Resolver, ResolverData};
24use crate::substitution::SemanticRewriter;
25use crate::{Mutability, Parameter, SemanticDiagnostic, TypeId, semantic};
26
27#[cfg(test)]
28#[path = "extern_function_test.rs"]
29mod test;
30
31// --- Selectors ---
32
33/// Query implementation of [crate::db::SemanticGroup::extern_function_declaration_inline_config].
34pub fn extern_function_declaration_inline_config(
35    db: &dyn SemanticGroup,
36    extern_function_id: ExternFunctionId,
37) -> Maybe<InlineConfiguration> {
38    Ok(db.priv_extern_function_declaration_data(extern_function_id)?.inline_config)
39}
40// TODO(spapini): Remove declaration from the names.
41/// Query implementation of [crate::db::SemanticGroup::extern_function_declaration_diagnostics].
42pub fn extern_function_declaration_diagnostics(
43    db: &dyn SemanticGroup,
44    extern_function_id: ExternFunctionId,
45) -> Diagnostics<SemanticDiagnostic> {
46    db.priv_extern_function_declaration_data(extern_function_id)
47        .map(|data| data.diagnostics)
48        .unwrap_or_default()
49}
50/// Query implementation of [crate::db::SemanticGroup::extern_function_signature].
51pub fn extern_function_signature(
52    db: &dyn SemanticGroup,
53    extern_function_id: ExternFunctionId,
54) -> Maybe<semantic::Signature> {
55    Ok(db.priv_extern_function_declaration_data(extern_function_id)?.signature)
56}
57/// Query implementation of [crate::db::SemanticGroup::extern_function_declaration_generic_params].
58pub fn extern_function_declaration_generic_params(
59    db: &dyn SemanticGroup,
60    extern_function_id: ExternFunctionId,
61) -> Maybe<Vec<semantic::GenericParam>> {
62    Ok(db.extern_function_declaration_generic_params_data(extern_function_id)?.generic_params)
63}
64
65/// Query implementation of
66/// [crate::db::SemanticGroup::extern_function_declaration_generic_params_data].
67pub fn extern_function_declaration_generic_params_data(
68    db: &dyn SemanticGroup,
69    extern_function_id: ExternFunctionId,
70) -> Maybe<GenericParamsData> {
71    let syntax_db = db.upcast();
72    let module_file_id = extern_function_id.module_file_id(db.upcast());
73    let mut diagnostics = SemanticDiagnostics::default();
74    let extern_function_syntax = db.module_extern_function_by_id(extern_function_id)?.to_maybe()?;
75    let declaration = extern_function_syntax.declaration(syntax_db);
76
77    // Generic params.
78    let inference_id = InferenceId::LookupItemGenerics(LookupItemId::ModuleItem(
79        ModuleItemId::ExternFunction(extern_function_id),
80    ));
81    let mut resolver = Resolver::new(db, module_file_id, inference_id);
82    resolver.set_feature_config(&extern_function_id, &extern_function_syntax, &mut diagnostics);
83    let generic_params = semantic_generic_params(
84        db,
85        &mut diagnostics,
86        &mut resolver,
87        module_file_id,
88        &declaration.generic_params(syntax_db),
89    );
90
91    let inference = &mut resolver.inference();
92    inference.finalize(&mut diagnostics, extern_function_syntax.stable_ptr().untyped());
93
94    let generic_params = inference.rewrite(generic_params).no_err();
95    let resolver_data = Arc::new(resolver.data);
96    Ok(GenericParamsData { diagnostics: diagnostics.build(), generic_params, resolver_data })
97}
98
99/// Query implementation of [crate::db::SemanticGroup::extern_function_declaration_implicits].
100pub fn extern_function_declaration_implicits(
101    db: &dyn SemanticGroup,
102    extern_function_id: ExternFunctionId,
103) -> Maybe<Vec<TypeId>> {
104    Ok(db.priv_extern_function_declaration_data(extern_function_id)?.signature.implicits)
105}
106
107/// Query implementation of [crate::db::SemanticGroup::extern_function_declaration_refs].
108pub fn extern_function_declaration_refs(
109    db: &dyn SemanticGroup,
110    extern_function_id: ExternFunctionId,
111) -> Maybe<Vec<Parameter>> {
112    Ok(db
113        .priv_extern_function_declaration_data(extern_function_id)?
114        .signature
115        .params
116        .into_iter()
117        .filter(|param| param.mutability == Mutability::Reference)
118        .collect())
119}
120
121/// Query implementation of
122/// [crate::db::SemanticGroup::extern_function_declaration_resolver_data].
123pub fn extern_function_declaration_resolver_data(
124    db: &dyn SemanticGroup,
125    extern_function_id: ExternFunctionId,
126) -> Maybe<Arc<ResolverData>> {
127    Ok(db.priv_extern_function_declaration_data(extern_function_id)?.resolver_data)
128}
129
130// --- Computation ---
131
132/// Query implementation of [crate::db::SemanticGroup::priv_extern_function_declaration_data].
133pub fn priv_extern_function_declaration_data(
134    db: &dyn SemanticGroup,
135    extern_function_id: ExternFunctionId,
136) -> Maybe<FunctionDeclarationData> {
137    let syntax_db = db.upcast();
138    let mut diagnostics = SemanticDiagnostics::default();
139    let extern_function_syntax = db.module_extern_function_by_id(extern_function_id)?.to_maybe()?;
140
141    let declaration = extern_function_syntax.declaration(syntax_db);
142
143    // Generic params.
144    let generic_params_data =
145        db.extern_function_declaration_generic_params_data(extern_function_id)?;
146    let generic_params = generic_params_data.generic_params;
147    let lookup_item_id = LookupItemId::ModuleItem(ModuleItemId::ExternFunction(extern_function_id));
148    let inference_id = InferenceId::LookupItemDeclaration(lookup_item_id);
149    let mut resolver = Resolver::with_data(
150        db,
151        (*generic_params_data.resolver_data).clone_with_inference_id(db, inference_id),
152    );
153    diagnostics.extend(generic_params_data.diagnostics);
154    resolver.set_feature_config(&extern_function_id, &extern_function_syntax, &mut diagnostics);
155
156    let mut environment = Environment::empty();
157    let signature_syntax = declaration.signature(syntax_db);
158    let signature = semantic::Signature::from_ast(
159        &mut diagnostics,
160        db,
161        &mut resolver,
162        &signature_syntax,
163        FunctionTitleId::Extern(extern_function_id),
164        &mut environment,
165    );
166
167    if signature.panicable {
168        let panic_function = extract_matches!(
169            get_core_generic_function_id(db.upcast(), "panic".into()),
170            GenericFunctionId::Extern
171        );
172        if extern_function_id != panic_function {
173            diagnostics.report(&extern_function_syntax, PanicableExternFunction);
174        }
175    }
176
177    let attributes = extern_function_syntax.attributes(syntax_db).structurize(syntax_db);
178    let inline_config = get_inline_config(db, &mut diagnostics, &attributes)?;
179
180    match &inline_config {
181        InlineConfiguration::None => {}
182        InlineConfiguration::Always(attr)
183        | InlineConfiguration::Never(attr)
184        | InlineConfiguration::Should(attr) => {
185            diagnostics.report(attr.stable_ptr.untyped(), InlineAttrForExternFunctionNotAllowed);
186        }
187    }
188
189    let (_, implicit_precedence_attr) =
190        get_implicit_precedence(&mut diagnostics, &mut resolver, &attributes);
191    if let Some(attr) = implicit_precedence_attr {
192        diagnostics
193            .report(attr.stable_ptr.untyped(), ImplicitPrecedenceAttrForExternFunctionNotAllowed);
194    }
195
196    // Check fully resolved.
197    let inference = &mut resolver.inference();
198    inference.finalize(&mut diagnostics, extern_function_syntax.stable_ptr().untyped());
199
200    let signature = inference.rewrite(signature).no_err();
201    let generic_params = inference.rewrite(generic_params).no_err();
202
203    Ok(FunctionDeclarationData {
204        diagnostics: diagnostics.build(),
205        signature,
206        environment,
207        generic_params,
208        attributes,
209        resolver_data: Arc::new(resolver.data),
210        inline_config,
211        implicit_precedence: ImplicitPrecedence::UNSPECIFIED,
212    })
213}