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 = semantic::Signature::from_ast(
158        &mut diagnostics,
159        db,
160        &mut resolver,
161        &declaration,
162        FunctionTitleId::Extern(extern_function_id),
163        &mut environment,
164    );
165
166    if signature.panicable {
167        let panic_function = extract_matches!(
168            get_core_generic_function_id(db.upcast(), "panic".into()),
169            GenericFunctionId::Extern
170        );
171        if extern_function_id != panic_function {
172            diagnostics.report(&extern_function_syntax, PanicableExternFunction);
173        }
174    }
175
176    let attributes = extern_function_syntax.attributes(syntax_db).structurize(syntax_db);
177    let inline_config = get_inline_config(db, &mut diagnostics, &attributes)?;
178
179    match &inline_config {
180        InlineConfiguration::None => {}
181        InlineConfiguration::Always(attr)
182        | InlineConfiguration::Never(attr)
183        | InlineConfiguration::Should(attr) => {
184            diagnostics.report(attr.stable_ptr.untyped(), InlineAttrForExternFunctionNotAllowed);
185        }
186    }
187
188    let (_, implicit_precedence_attr) =
189        get_implicit_precedence(&mut diagnostics, &mut resolver, &attributes);
190    if let Some(attr) = implicit_precedence_attr {
191        diagnostics
192            .report(attr.stable_ptr.untyped(), ImplicitPrecedenceAttrForExternFunctionNotAllowed);
193    }
194
195    // Check fully resolved.
196    let inference = &mut resolver.inference();
197    inference.finalize(&mut diagnostics, extern_function_syntax.stable_ptr().untyped());
198
199    let signature = inference.rewrite(signature).no_err();
200    let generic_params = inference.rewrite(generic_params).no_err();
201
202    Ok(FunctionDeclarationData {
203        diagnostics: diagnostics.build(),
204        signature,
205        environment,
206        generic_params,
207        attributes,
208        resolver_data: Arc::new(resolver.data),
209        inline_config,
210        implicit_precedence: ImplicitPrecedence::UNSPECIFIED,
211    })
212}