cairo_lang_semantic/items/
extern_function.rs1use 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
31pub 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}
40pub 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}
50pub 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}
57pub 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
65pub 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 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
99pub 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
107pub 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
121pub 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
130pub 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 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 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}