cairo_lang_semantic/items/
extern_function.rs1use std::sync::Arc;
2
3use cairo_lang_defs::db::DefsGroup;
4use cairo_lang_defs::ids::{
5 ExternFunctionId, FunctionTitleId, LanguageElementId, LookupItemId, ModuleItemId,
6};
7use cairo_lang_diagnostics::{Diagnostics, Maybe, MaybeAsRef};
8use cairo_lang_filesystem::ids::SmolStrId;
9use cairo_lang_syntax::attribute::structured::AttributeListStructurize;
10use cairo_lang_syntax::node::{TypedStablePtr, TypedSyntaxNode};
11use cairo_lang_utils::extract_matches;
12use salsa::Database;
13
14use super::function_with_body::get_inline_config;
15use super::functions::{FunctionDeclarationData, GenericFunctionId, InlineConfiguration};
16use super::generics::{GenericParamsData, semantic_generic_params};
17use super::report_extern_item_outside_corelib;
18use crate::corelib::get_core_generic_function_id;
19use crate::diagnostic::SemanticDiagnosticKind::*;
20use crate::diagnostic::{SemanticDiagnostics, SemanticDiagnosticsBuilder};
21use crate::expr::compute::Environment;
22use crate::expr::inference::InferenceId;
23use crate::expr::inference::canonic::ResultNoErrEx;
24use crate::items::function_with_body::get_implicit_precedence;
25use crate::items::functions::ImplicitPrecedence;
26use crate::resolve::{Resolver, ResolverData};
27use crate::substitution::SemanticRewriter;
28use crate::{GenericParam, SemanticDiagnostic, semantic};
29
30#[cfg(test)]
31#[path = "extern_function_test.rs"]
32mod test;
33
34#[salsa::tracked(returns(ref))]
37fn extern_function_declaration_generic_params_data<'db>(
38 db: &'db dyn Database,
39 extern_function_id: ExternFunctionId<'db>,
40) -> Maybe<GenericParamsData<'db>> {
41 let module_id = extern_function_id.parent_module(db);
42 let mut diagnostics = SemanticDiagnostics::new(module_id);
43 let extern_function_syntax = db.module_extern_function_by_id(extern_function_id)?;
44 let declaration = extern_function_syntax.declaration(db);
45
46 let inference_id = InferenceId::LookupItemGenerics(LookupItemId::ModuleItem(
48 ModuleItemId::ExternFunction(extern_function_id),
49 ));
50 let mut resolver = Resolver::new(db, module_id, inference_id);
51 resolver.set_feature_config(&extern_function_id, &extern_function_syntax, &mut diagnostics);
52 let generic_params = semantic_generic_params(
53 db,
54 &mut diagnostics,
55 &mut resolver,
56 module_id,
57 &declaration.generic_params(db),
58 );
59
60 let inference = &mut resolver.inference();
61 inference.finalize(&mut diagnostics, extern_function_syntax.stable_ptr(db).untyped());
62
63 let generic_params = inference.rewrite(generic_params).no_err();
64 let resolver_data = Arc::new(resolver.data);
65 Ok(GenericParamsData { diagnostics: diagnostics.build(), generic_params, resolver_data })
66}
67
68#[salsa::tracked(returns(ref))]
70fn priv_extern_function_declaration_data<'db>(
71 db: &'db dyn Database,
72 extern_function_id: ExternFunctionId<'db>,
73) -> Maybe<FunctionDeclarationData<'db>> {
74 let mut diagnostics = SemanticDiagnostics::new(extern_function_id.parent_module(db));
75 let extern_function_syntax = db.module_extern_function_by_id(extern_function_id)?;
76
77 let declaration = extern_function_syntax.declaration(db);
78
79 let generic_params_data =
81 db.extern_function_declaration_generic_params_data(extern_function_id)?;
82 let lookup_item_id = LookupItemId::ModuleItem(ModuleItemId::ExternFunction(extern_function_id));
83 let inference_id = InferenceId::LookupItemDeclaration(lookup_item_id);
84 let mut resolver = Resolver::with_data(
85 db,
86 (*generic_params_data.resolver_data).clone_with_inference_id(db, inference_id),
87 );
88 diagnostics.extend(generic_params_data.diagnostics.clone());
89 resolver.set_feature_config(&extern_function_id, &extern_function_syntax, &mut diagnostics);
90
91 let mut environment = Environment::empty();
92 let signature = semantic::Signature::from_ast(
93 &mut diagnostics,
94 db,
95 &mut resolver,
96 &declaration,
97 FunctionTitleId::Extern(extern_function_id),
98 &mut environment,
99 );
100
101 report_extern_item_outside_corelib(db, &mut diagnostics, &resolver, &extern_function_syntax);
102
103 if signature.panicable {
104 let panic_function = extract_matches!(
105 get_core_generic_function_id(db, SmolStrId::from(db, "panic")),
106 GenericFunctionId::Extern
107 );
108 if extern_function_id != panic_function {
109 diagnostics.report(extern_function_syntax.stable_ptr(db), PanicableExternFunction);
110 }
111 }
112
113 let attributes = extern_function_syntax.attributes(db).structurize(db);
114 let inline_config = get_inline_config(db, &mut diagnostics, &attributes)?;
115
116 match &inline_config {
117 InlineConfiguration::None => {}
118 InlineConfiguration::Always(stable_ptr)
119 | InlineConfiguration::Never(stable_ptr)
120 | InlineConfiguration::Should(stable_ptr) => {
121 diagnostics.report(stable_ptr.untyped(), InlineAttrForExternFunctionNotAllowed);
122 }
123 }
124
125 let (_, implicit_precedence_attr) =
126 get_implicit_precedence(db, &mut diagnostics, &mut resolver, &attributes);
127 if let Some(attr) = implicit_precedence_attr {
128 diagnostics
129 .report(attr.stable_ptr.untyped(), ImplicitPrecedenceAttrForExternFunctionNotAllowed);
130 }
131
132 let inference = &mut resolver.inference();
134 inference.finalize(&mut diagnostics, extern_function_syntax.stable_ptr(db).untyped());
135
136 let signature = inference.rewrite(signature).no_err();
137
138 Ok(FunctionDeclarationData {
139 diagnostics: diagnostics.build(),
140 signature,
141 environment,
142 attributes,
143 resolver_data: Arc::new(resolver.data),
144 inline_config,
145 implicit_precedence: ImplicitPrecedence::UNSPECIFIED,
146 })
147}
148
149pub trait ExternFunctionSemantic<'db>: Database {
151 fn extern_function_declaration_inline_config(
153 &'db self,
154 extern_function_id: ExternFunctionId<'db>,
155 ) -> Maybe<InlineConfiguration<'db>> {
156 Ok(self.priv_extern_function_declaration_data(extern_function_id)?.inline_config.clone())
157 }
158 fn extern_function_declaration_diagnostics(
161 &'db self,
162 extern_function_id: ExternFunctionId<'db>,
163 ) -> Diagnostics<'db, SemanticDiagnostic<'db>> {
164 self.priv_extern_function_declaration_data(extern_function_id)
165 .map(|data| data.diagnostics.clone())
166 .unwrap_or_default()
167 }
168 fn extern_function_signature(
170 &'db self,
171 extern_function_id: ExternFunctionId<'db>,
172 ) -> Maybe<&'db semantic::Signature<'db>> {
173 Ok(&self.priv_extern_function_declaration_data(extern_function_id)?.signature)
174 }
175 fn extern_function_declaration_generic_params(
177 &'db self,
178 extern_function_id: ExternFunctionId<'db>,
179 ) -> Maybe<&'db [GenericParam<'db>]> {
180 Ok(&self
181 .extern_function_declaration_generic_params_data(extern_function_id)?
182 .generic_params)
183 }
184 fn extern_function_declaration_resolver_data(
186 &'db self,
187 extern_function_id: ExternFunctionId<'db>,
188 ) -> Maybe<Arc<ResolverData<'db>>> {
189 Ok(self.priv_extern_function_declaration_data(extern_function_id)?.resolver_data.clone())
190 }
191}
192impl<'db, T: Database + ?Sized> ExternFunctionSemantic<'db> for T {}
193
194trait PrivExternFunctionSemantic<'db>: Database {
196 fn priv_extern_function_declaration_data(
199 &'db self,
200 function_id: ExternFunctionId<'db>,
201 ) -> Maybe<&'db FunctionDeclarationData<'db>> {
202 priv_extern_function_declaration_data(self.as_dyn_database(), function_id).maybe_as_ref()
203 }
204 fn extern_function_declaration_generic_params_data(
206 &'db self,
207 extern_function_id: ExternFunctionId<'db>,
208 ) -> Maybe<&'db GenericParamsData<'db>> {
209 extern_function_declaration_generic_params_data(self.as_dyn_database(), extern_function_id)
210 .maybe_as_ref()
211 }
212}
213impl<'db, T: Database + ?Sized> PrivExternFunctionSemantic<'db> for T {}