1use std::sync::Arc;
2
3use cairo_lang_debug::DebugWithDb;
4use cairo_lang_defs::diagnostic_utils::StableLocation;
5use cairo_lang_defs::ids::{
6 ExternFunctionId, FreeFunctionId, FunctionTitleId, FunctionWithBodyId, ImplFunctionId,
7 LanguageElementId, ModuleFileId, ModuleItemId, NamedLanguageElementId, ParamLongId,
8 TopLevelLanguageElementId, TraitFunctionId,
9};
10use cairo_lang_diagnostics::{Diagnostics, Maybe};
11use cairo_lang_filesystem::ids::UnstableSalsaId;
12use cairo_lang_proc_macros::{DebugWithDb, SemanticObject};
13use cairo_lang_syntax as syntax;
14use cairo_lang_syntax::attribute::structured::Attribute;
15use cairo_lang_syntax::node::{Terminal, TypedSyntaxNode, ast};
16use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
17use cairo_lang_utils::{
18 Intern, LookupIntern, OptionFrom, define_short_id, require, try_extract_matches,
19};
20use itertools::{Itertools, chain};
21use smol_str::SmolStr;
22use syntax::attribute::consts::MUST_USE_ATTR;
23use syntax::node::TypedStablePtr;
24
25use super::attribute::SemanticQueryAttrs;
26use super::generics::{fmt_generic_args, generic_params_to_args};
27use super::imp::{ImplId, ImplLongId};
28use super::modifiers;
29use super::trt::ConcreteTraitGenericFunctionId;
30use crate::corelib::{fn_traits, unit_ty};
31use crate::db::SemanticGroup;
32use crate::diagnostic::{SemanticDiagnosticKind, SemanticDiagnostics, SemanticDiagnosticsBuilder};
33use crate::expr::compute::Environment;
34use crate::resolve::{Resolver, ResolverData};
35use crate::substitution::GenericSubstitution;
36use crate::types::resolve_type;
37use crate::{
38 ConcreteImplId, ConcreteImplLongId, ConcreteTraitLongId, GenericArgumentId, GenericParam,
39 SemanticDiagnostic, TypeId, semantic, semantic_object_for_id,
40};
41
42#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
44pub struct ImplGenericFunctionId {
45 pub impl_id: ImplId,
48 pub function: TraitFunctionId,
50}
51impl ImplGenericFunctionId {
52 pub fn impl_function(&self, db: &dyn SemanticGroup) -> Maybe<Option<ImplFunctionId>> {
54 match self.impl_id.lookup_intern(db) {
55 ImplLongId::Concrete(concrete_impl_id) => {
56 concrete_impl_id.get_impl_function(db, self.function)
57 }
58 ImplLongId::GenericParameter(_)
59 | ImplLongId::ImplVar(_)
60 | ImplLongId::ImplImpl(_)
61 | ImplLongId::SelfImpl(_)
62 | ImplLongId::GeneratedImpl(_) => Ok(None),
63 }
64 }
65 pub fn format(&self, db: &dyn SemanticGroup) -> SmolStr {
66 format!("{}::{}", self.impl_id.name(db), self.function.name(db)).into()
67 }
68}
69impl DebugWithDb<dyn SemanticGroup> for ImplGenericFunctionId {
70 fn fmt(
71 &self,
72 f: &mut std::fmt::Formatter<'_>,
73 db: &(dyn SemanticGroup + 'static),
74 ) -> std::fmt::Result {
75 write!(f, "{}", self.format(db))
76 }
77}
78
79#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
81pub enum GenericFunctionId {
82 Free(FreeFunctionId),
84 Extern(ExternFunctionId),
86 Impl(ImplGenericFunctionId),
88}
89impl GenericFunctionId {
90 pub fn from_generic_with_body(
91 db: &dyn SemanticGroup,
92 val: GenericFunctionWithBodyId,
93 ) -> Maybe<Self> {
94 Ok(match val {
95 GenericFunctionWithBodyId::Free(id) => GenericFunctionId::Free(id),
96 GenericFunctionWithBodyId::Impl(id) => {
97 let impl_id = ImplLongId::Concrete(id.concrete_impl_id).intern(db);
98 let function = match id.function_body {
99 ImplFunctionBodyId::Impl(body_id) => {
100 db.impl_function_trait_function(body_id)?
101 }
102 ImplFunctionBodyId::Trait(body_id) => body_id,
103 };
104 GenericFunctionId::Impl(ImplGenericFunctionId { impl_id, function })
105 }
106 GenericFunctionWithBodyId::Trait(id) => {
107 GenericFunctionId::Impl(ImplGenericFunctionId {
108 impl_id: ImplLongId::SelfImpl(id.concrete_trait(db)).intern(db),
109 function: id.trait_function(db),
110 })
111 }
112 })
113 }
114 pub fn format(&self, db: &dyn SemanticGroup) -> String {
115 match self {
116 GenericFunctionId::Free(id) => id.full_path(db),
117 GenericFunctionId::Extern(id) => id.full_path(db),
118 GenericFunctionId::Impl(id) => {
119 format!("{:?}::{}", id.impl_id.debug(db.elongate()), id.function.name(db))
120 }
121 }
122 }
123 pub fn generic_signature(&self, db: &dyn SemanticGroup) -> Maybe<Signature> {
124 match *self {
125 GenericFunctionId::Free(id) => db.free_function_signature(id),
126 GenericFunctionId::Extern(id) => db.extern_function_signature(id),
127 GenericFunctionId::Impl(id) => {
128 let concrete_trait_id = id.impl_id.concrete_trait(db)?;
129 let signature = db.concrete_trait_function_signature(
130 ConcreteTraitGenericFunctionId::new(db, concrete_trait_id, id.function),
131 )?;
132
133 GenericSubstitution::from_impl(id.impl_id).substitute(db, signature)
134 }
135 }
136 }
137 pub fn generic_params(&self, db: &dyn SemanticGroup) -> Maybe<Vec<GenericParam>> {
138 match *self {
139 GenericFunctionId::Free(id) => db.free_function_generic_params(id),
140 GenericFunctionId::Extern(id) => db.extern_function_declaration_generic_params(id),
141 GenericFunctionId::Impl(id) => {
142 let concrete_trait_id = db.impl_concrete_trait(id.impl_id)?;
143 let concrete_id =
144 ConcreteTraitGenericFunctionId::new(db, concrete_trait_id, id.function);
145 GenericSubstitution::from_impl(id.impl_id)
146 .substitute(db, db.concrete_trait_function_generic_params(concrete_id)?)
147 }
148 }
149 }
150 pub fn name(&self, db: &dyn SemanticGroup) -> SmolStr {
151 match self {
152 GenericFunctionId::Free(free_function) => free_function.name(db),
153 GenericFunctionId::Extern(extern_function) => extern_function.name(db),
154 GenericFunctionId::Impl(impl_function) => impl_function.format(db),
155 }
156 }
157 pub fn module_file_id(&self, db: &dyn SemanticGroup) -> Option<ModuleFileId> {
159 match self {
160 GenericFunctionId::Free(free_function) => Some(free_function.module_file_id(db)),
161 GenericFunctionId::Extern(extern_function) => Some(extern_function.module_file_id(db)),
162 GenericFunctionId::Impl(impl_generic_function_id) => {
163 if let ImplLongId::Concrete(concrete_impl_id) =
165 impl_generic_function_id.impl_id.lookup_intern(db)
166 {
167 Some(concrete_impl_id.impl_def_id(db).module_file_id(db))
168 } else {
169 None
170 }
171 }
172 }
173 }
174 pub fn is_must_use(&self, db: &dyn SemanticGroup) -> Maybe<bool> {
176 match self {
177 GenericFunctionId::Free(id) => id.has_attr(db, MUST_USE_ATTR),
178 GenericFunctionId::Impl(id) => id.function.has_attr(db, MUST_USE_ATTR),
179 GenericFunctionId::Extern(_) => Ok(false),
180 }
181 }
182 pub fn is_fully_concrete(&self, db: &dyn SemanticGroup) -> bool {
184 match self {
185 GenericFunctionId::Free(_) | GenericFunctionId::Extern(_) => true,
186 GenericFunctionId::Impl(impl_generic_function) => {
187 impl_generic_function.impl_id.is_fully_concrete(db)
188 }
189 }
190 }
191 pub fn is_var_free(&self, db: &dyn SemanticGroup) -> bool {
193 match self {
194 GenericFunctionId::Free(_) | GenericFunctionId::Extern(_) => true,
195 GenericFunctionId::Impl(impl_generic_function) => {
196 impl_generic_function.impl_id.is_var_free(db)
197 }
198 }
199 }
200 pub fn concretize(
202 &self,
203 db: &dyn SemanticGroup,
204 generic_args: Vec<semantic::GenericArgumentId>,
205 ) -> FunctionId {
206 FunctionLongId { function: ConcreteFunction { generic_function: *self, generic_args } }
207 .intern(db)
208 }
209}
210impl OptionFrom<ModuleItemId> for GenericFunctionId {
212 fn option_from(item: ModuleItemId) -> Option<Self> {
213 match item {
214 ModuleItemId::FreeFunction(id) => Some(GenericFunctionId::Free(id)),
215 ModuleItemId::ExternFunction(id) => Some(GenericFunctionId::Extern(id)),
216 ModuleItemId::Constant(_)
217 | ModuleItemId::Submodule(_)
218 | ModuleItemId::Use(_)
219 | ModuleItemId::Trait(_)
220 | ModuleItemId::Impl(_)
221 | ModuleItemId::Struct(_)
222 | ModuleItemId::Enum(_)
223 | ModuleItemId::TypeAlias(_)
224 | ModuleItemId::ImplAlias(_)
225 | ModuleItemId::ExternType(_) => None,
226 }
227 }
228}
229impl DebugWithDb<dyn SemanticGroup> for GenericFunctionId {
230 fn fmt(
231 &self,
232 f: &mut std::fmt::Formatter<'_>,
233 db: &(dyn SemanticGroup + 'static),
234 ) -> std::fmt::Result {
235 match self {
236 GenericFunctionId::Free(func) => write!(f, "{:?}", func.debug(db)),
237 GenericFunctionId::Extern(func) => write!(f, "{:?}", func.debug(db)),
238 GenericFunctionId::Impl(func) => write!(f, "{:?}", func.debug(db)),
239 }
240 }
241}
242
243#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
247pub struct FunctionLongId {
248 pub function: ConcreteFunction,
249}
250impl DebugWithDb<dyn SemanticGroup> for FunctionLongId {
251 fn fmt(
252 &self,
253 f: &mut std::fmt::Formatter<'_>,
254 db: &(dyn SemanticGroup + 'static),
255 ) -> std::fmt::Result {
256 write!(f, "{:?}", self.function.debug(db))
257 }
258}
259
260define_short_id!(
261 FunctionId,
262 FunctionLongId,
263 SemanticGroup,
264 lookup_intern_function,
265 intern_function
266);
267semantic_object_for_id!(FunctionId, lookup_intern_function, intern_function, FunctionLongId);
268impl FunctionId {
269 pub fn get_concrete(&self, db: &dyn SemanticGroup) -> ConcreteFunction {
270 self.lookup_intern(db).function
271 }
272
273 pub fn try_get_extern_function_id(&self, db: &dyn SemanticGroup) -> Option<ExternFunctionId> {
275 try_extract_matches!(self.get_concrete(db).generic_function, GenericFunctionId::Extern)
276 }
277
278 pub fn name(&self, db: &dyn SemanticGroup) -> SmolStr {
279 format!("{:?}", self.get_concrete(db).generic_function.name(db)).into()
280 }
281
282 pub fn full_path(&self, db: &dyn SemanticGroup) -> String {
283 self.get_concrete(db).full_path(db)
284 }
285
286 pub fn is_fully_concrete(&self, db: &dyn SemanticGroup) -> bool {
288 let func = self.get_concrete(db);
289 func.generic_function.is_fully_concrete(db)
290 && func
291 .generic_args
292 .iter()
293 .all(|generic_argument_id| generic_argument_id.is_fully_concrete(db))
294 }
295 pub fn is_var_free(&self, db: &dyn SemanticGroup) -> bool {
297 let func = self.get_concrete(db);
298 func.generic_function.is_var_free(db)
299 && func
300 .generic_args
301 .iter()
302 .all(|generic_argument_id| generic_argument_id.is_var_free(db))
303 }
304}
305impl FunctionLongId {
306 pub fn from_generic(
307 db: &dyn SemanticGroup,
308 generic_function: GenericFunctionId,
309 ) -> Maybe<Self> {
310 let generic_params: Vec<_> = generic_function.generic_params(db)?;
311
312 Ok(FunctionLongId {
313 function: ConcreteFunction {
314 generic_function,
315 generic_args: generic_params_to_args(&generic_params, db),
316 },
317 })
318 }
319}
320
321#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
323pub struct ImplGenericFunctionWithBodyId {
324 pub concrete_impl_id: ConcreteImplId,
325 pub function_body: ImplFunctionBodyId,
326}
327
328#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
330pub enum ImplFunctionBodyId {
331 Impl(ImplFunctionId),
333 Trait(TraitFunctionId),
335}
336impl ImplFunctionBodyId {
337 pub fn name(&self, db: &dyn SemanticGroup) -> SmolStr {
338 match self {
339 Self::Impl(body_id) => body_id.name(db),
340 Self::Trait(body_id) => body_id.name(db),
341 }
342 }
343 pub fn stable_location(&self, db: &dyn SemanticGroup) -> StableLocation {
344 match self {
345 Self::Impl(body_id) => body_id.stable_location(db),
346 Self::Trait(body_id) => body_id.stable_location(db),
347 }
348 }
349
350 pub fn trait_function(&self, db: &dyn SemanticGroup) -> Maybe<TraitFunctionId> {
351 match self {
352 Self::Impl(impl_function) => db.impl_function_trait_function(*impl_function),
353 Self::Trait(trait_function) => Ok(*trait_function),
354 }
355 }
356}
357
358#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
360pub enum GenericFunctionWithBodyId {
361 Free(FreeFunctionId),
362 Impl(ImplGenericFunctionWithBodyId),
363 Trait(ConcreteTraitGenericFunctionId),
364}
365impl GenericFunctionWithBodyId {
366 pub fn from_generic(db: &dyn SemanticGroup, other: GenericFunctionId) -> Maybe<Option<Self>> {
367 Ok(Some(match other {
368 GenericFunctionId::Free(id) => GenericFunctionWithBodyId::Free(id),
369 GenericFunctionId::Impl(ImplGenericFunctionId { impl_id, function }) => {
370 let ImplLongId::Concrete(concrete_impl_id) = impl_id.lookup_intern(db) else {
371 return Ok(None);
372 };
373 GenericFunctionWithBodyId::Impl(ImplGenericFunctionWithBodyId {
374 concrete_impl_id,
375 function_body: if let Some(impl_function) =
376 concrete_impl_id.get_impl_function(db, function)?
377 {
378 ImplFunctionBodyId::Impl(impl_function)
379 } else {
380 ImplFunctionBodyId::Trait(function)
381 },
382 })
383 }
384 _ => return Ok(None),
385 }))
386 }
387 pub fn name(&self, db: &dyn SemanticGroup) -> SmolStr {
388 match self {
389 GenericFunctionWithBodyId::Free(free) => free.name(db),
390 GenericFunctionWithBodyId::Impl(imp) => {
391 format!("{}::{}", imp.concrete_impl_id.name(db), imp.function_body.name(db)).into()
392 }
393 GenericFunctionWithBodyId::Trait(trt) => {
394 format!("{}::{}", trt.concrete_trait(db).name(db), trt.trait_function(db).name(db))
395 .into()
396 }
397 }
398 }
399
400 pub fn full_path(&self, db: &dyn SemanticGroup) -> String {
401 match self {
402 GenericFunctionWithBodyId::Free(free) => free.full_path(db),
403 GenericFunctionWithBodyId::Impl(imp) => {
404 format!(
405 "{}::{}",
406 imp.concrete_impl_id.impl_def_id(db).full_path(db),
407 imp.function_body.name(db)
408 )
409 }
410 GenericFunctionWithBodyId::Trait(trt) => format!(
411 "{}::{}",
412 trt.concrete_trait(db).full_path(db),
413 trt.trait_function(db).name(db)
414 ),
415 }
416 }
417 pub fn stable_location(&self, db: &dyn SemanticGroup) -> StableLocation {
418 match self {
419 GenericFunctionWithBodyId::Free(free_function) => free_function.stable_location(db),
420 GenericFunctionWithBodyId::Impl(impl_function) => {
421 impl_function.function_body.stable_location(db)
422 }
423 GenericFunctionWithBodyId::Trait(trait_function) => {
424 trait_function.trait_function(db).stable_location(db)
425 }
426 }
427 }
428}
429
430#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
432pub struct ConcreteFunctionWithBody {
433 pub generic_function: GenericFunctionWithBodyId,
434 pub generic_args: Vec<semantic::GenericArgumentId>,
435}
436impl ConcreteFunctionWithBody {
437 pub fn function_with_body_id(&self, db: &dyn SemanticGroup) -> FunctionWithBodyId {
438 match self.generic_function {
439 GenericFunctionWithBodyId::Free(id) => FunctionWithBodyId::Free(id),
440 GenericFunctionWithBodyId::Impl(id) => match id.function_body {
441 ImplFunctionBodyId::Impl(id) => FunctionWithBodyId::Impl(id),
442 ImplFunctionBodyId::Trait(id) => FunctionWithBodyId::Trait(id),
443 },
444 GenericFunctionWithBodyId::Trait(id) => {
445 FunctionWithBodyId::Trait(id.trait_function(db))
446 }
447 }
448 }
449 pub fn substitution(&self, db: &dyn SemanticGroup) -> Maybe<GenericSubstitution> {
450 Ok(match self.generic_function {
451 GenericFunctionWithBodyId::Free(f) => {
452 GenericSubstitution::new(&db.free_function_generic_params(f)?, &self.generic_args)
453 }
454 GenericFunctionWithBodyId::Impl(f) => match f.function_body {
455 ImplFunctionBodyId::Impl(body_id) => {
456 let concrete_impl = f.concrete_impl_id.lookup_intern(db);
457 GenericSubstitution::from_impl(
458 ImplLongId::Concrete(f.concrete_impl_id).intern(db),
459 )
460 .concat(GenericSubstitution::new(
461 &chain!(
462 db.impl_function_generic_params(body_id)?,
463 db.impl_def_generic_params(concrete_impl.impl_def_id)?
464 )
465 .collect_vec(),
466 &chain!(
467 self.generic_args.iter().copied(),
468 concrete_impl.generic_args.iter().copied()
469 )
470 .collect_vec(),
471 ))
472 }
473 ImplFunctionBodyId::Trait(body_id) => {
474 let concrete_impl_id = ImplLongId::Concrete(f.concrete_impl_id).intern(db);
475 let concrete_trait = concrete_impl_id.concrete_trait(db)?.lookup_intern(db);
476 GenericSubstitution::from_impl(concrete_impl_id).concat(
477 GenericSubstitution::new(
478 &chain!(
479 db.trait_function_generic_params(body_id)?,
480 db.trait_generic_params(concrete_trait.trait_id)?
481 )
482 .collect_vec(),
483 &chain!(
484 self.generic_args.iter().copied(),
485 concrete_trait.generic_args.iter().copied()
486 )
487 .collect_vec(),
488 ),
489 )
490 }
491 },
492 GenericFunctionWithBodyId::Trait(f) => {
493 let concrete_trait = f.concrete_trait(db).lookup_intern(db);
494 GenericSubstitution::new(
495 &chain!(
496 db.trait_function_generic_params(f.trait_function(db))?,
497 db.trait_generic_params(concrete_trait.trait_id)?
498 )
499 .collect_vec(),
500 &chain!(
501 self.generic_args.iter().copied(),
502 concrete_trait.generic_args.iter().copied()
503 )
504 .collect_vec(),
505 )
506 }
507 })
508 }
509 pub fn from_no_generics_free(
510 db: &dyn SemanticGroup,
511 free_function_id: FreeFunctionId,
512 ) -> Option<Self> {
513 require(db.free_function_generic_params(free_function_id).ok()?.is_empty())?;
514 Some(ConcreteFunctionWithBody {
515 generic_function: GenericFunctionWithBodyId::Free(free_function_id),
516 generic_args: vec![],
517 })
518 }
519 pub fn from_generic(db: &dyn SemanticGroup, function_id: FunctionWithBodyId) -> Maybe<Self> {
520 Ok(match function_id {
521 FunctionWithBodyId::Free(free) => {
522 let params = db.free_function_generic_params(free)?;
523 let generic_args = generic_params_to_args(¶ms, db);
524 ConcreteFunctionWithBody {
525 generic_function: GenericFunctionWithBodyId::Free(free),
526 generic_args,
527 }
528 }
529 FunctionWithBodyId::Impl(impl_function_id) => {
530 let params = db.impl_function_generic_params(impl_function_id)?;
531 let generic_args = generic_params_to_args(¶ms, db);
532 let impl_def_id = impl_function_id.impl_def_id(db);
533 let impl_def_params = db.impl_def_generic_params(impl_def_id)?;
534 let impl_generic_args = generic_params_to_args(&impl_def_params, db);
535 let impl_generic_function = ImplGenericFunctionWithBodyId {
536 concrete_impl_id: ConcreteImplLongId {
537 impl_def_id,
538 generic_args: impl_generic_args,
539 }
540 .intern(db),
541 function_body: ImplFunctionBodyId::Impl(impl_function_id),
542 };
543 ConcreteFunctionWithBody {
544 generic_function: GenericFunctionWithBodyId::Impl(impl_generic_function),
545 generic_args,
546 }
547 }
548 FunctionWithBodyId::Trait(trait_function_id) => {
549 let params = db.trait_function_generic_params(trait_function_id)?;
550 let generic_args = generic_params_to_args(¶ms, db);
551 let trait_id = trait_function_id.trait_id(db);
552 let trait_generic_params = db.trait_generic_params(trait_id)?;
553 let trait_generic_args = generic_params_to_args(&trait_generic_params, db);
554 let concrete_trait_id = ConcreteTraitLongId {
555 generic_args: trait_generic_args,
556 trait_id: trait_function_id.trait_id(db),
557 }
558 .intern(db);
559 let trait_generic_function =
560 ConcreteTraitGenericFunctionId::new(db, concrete_trait_id, trait_function_id);
561 ConcreteFunctionWithBody {
562 generic_function: GenericFunctionWithBodyId::Trait(trait_generic_function),
563 generic_args,
564 }
565 }
566 })
567 }
568 pub fn concrete(&self, db: &dyn SemanticGroup) -> Maybe<ConcreteFunction> {
569 Ok(ConcreteFunction {
570 generic_function: GenericFunctionId::from_generic_with_body(db, self.generic_function)?,
571 generic_args: self.generic_args.clone(),
572 })
573 }
574 pub fn function_id(&self, db: &dyn SemanticGroup) -> Maybe<FunctionId> {
575 Ok(FunctionLongId { function: self.concrete(db)? }.intern(db))
576 }
577 pub fn name(&self, db: &dyn SemanticGroup) -> SmolStr {
578 self.function_with_body_id(db).name(db)
579 }
580 pub fn full_path(&self, db: &dyn SemanticGroup) -> String {
581 format!("{:?}", self.debug(db.elongate()))
582 }
583}
584
585impl DebugWithDb<dyn SemanticGroup> for ConcreteFunctionWithBody {
586 fn fmt(
587 &self,
588 f: &mut std::fmt::Formatter<'_>,
589 db: &(dyn SemanticGroup + 'static),
590 ) -> std::fmt::Result {
591 write!(f, "{}", self.generic_function.full_path(db))?;
592 fmt_generic_args(&self.generic_args, f, db)
593 }
594}
595
596define_short_id!(
597 ConcreteFunctionWithBodyId,
598 ConcreteFunctionWithBody,
599 SemanticGroup,
600 lookup_intern_concrete_function_with_body,
601 intern_concrete_function_with_body
602);
603semantic_object_for_id!(
604 ConcreteFunctionWithBodyId,
605 lookup_intern_concrete_function_with_body,
606 intern_concrete_function_with_body,
607 ConcreteFunctionWithBody
608);
609impl ConcreteFunctionWithBodyId {
610 pub fn function_with_body_id(&self, db: &dyn SemanticGroup) -> FunctionWithBodyId {
611 self.lookup_intern(db).function_with_body_id(db)
612 }
613 pub fn substitution(&self, db: &dyn SemanticGroup) -> Maybe<GenericSubstitution> {
614 self.lookup_intern(db).substitution(db)
615 }
616 pub fn from_no_generics_free(
617 db: &dyn SemanticGroup,
618 free_function_id: FreeFunctionId,
619 ) -> Option<Self> {
620 Some(ConcreteFunctionWithBody::from_no_generics_free(db, free_function_id)?.intern(db))
621 }
622 pub fn from_generic(db: &dyn SemanticGroup, function_id: FunctionWithBodyId) -> Maybe<Self> {
623 Ok(ConcreteFunctionWithBody::from_generic(db, function_id)?.intern(db))
624 }
625 pub fn concrete(&self, db: &dyn SemanticGroup) -> Maybe<ConcreteFunction> {
626 self.lookup_intern(db).concrete(db)
627 }
628 pub fn function_id(&self, db: &dyn SemanticGroup) -> Maybe<FunctionId> {
629 self.lookup_intern(db).function_id(db)
630 }
631 pub fn generic_function(&self, db: &dyn SemanticGroup) -> GenericFunctionWithBodyId {
632 self.lookup_intern(db).generic_function
633 }
634 pub fn name(&self, db: &dyn SemanticGroup) -> SmolStr {
635 self.lookup_intern(db).name(db)
636 }
637 pub fn full_path(&self, db: &dyn SemanticGroup) -> String {
638 self.lookup_intern(db).full_path(db)
639 }
640
641 pub fn stable_location(&self, db: &dyn SemanticGroup) -> StableLocation {
642 self.lookup_intern(db).generic_function.stable_location(db)
643 }
644
645 pub fn is_panic_destruct_fn(&self, db: &dyn SemanticGroup) -> Maybe<bool> {
646 let trait_function = match self.generic_function(db) {
647 GenericFunctionWithBodyId::Free(_) => return Ok(false),
648 GenericFunctionWithBodyId::Impl(impl_func) => {
649 impl_func.function_body.trait_function(db)?
650 }
651 GenericFunctionWithBodyId::Trait(trait_func) => trait_func.trait_function(db),
652 };
653 Ok(trait_function == db.core_info().panic_destruct_fn)
654 }
655}
656
657impl UnstableSalsaId for ConcreteFunctionWithBodyId {
658 fn get_internal_id(&self) -> &salsa::InternId {
659 &self.0
660 }
661}
662
663#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
664pub struct ConcreteFunction {
665 pub generic_function: GenericFunctionId,
666 pub generic_args: Vec<semantic::GenericArgumentId>,
667}
668impl ConcreteFunction {
669 pub fn body(&self, db: &dyn SemanticGroup) -> Maybe<Option<ConcreteFunctionWithBodyId>> {
670 let Some(generic_function) =
671 GenericFunctionWithBodyId::from_generic(db, self.generic_function)?
672 else {
673 return Ok(None);
674 };
675 Ok(Some(
676 ConcreteFunctionWithBody { generic_function, generic_args: self.generic_args.clone() }
677 .intern(db),
678 ))
679 }
680 pub fn full_path(&self, db: &dyn SemanticGroup) -> String {
681 format!("{:?}", self.debug(db.elongate()))
682 }
683}
684impl DebugWithDb<dyn SemanticGroup> for ConcreteFunction {
685 fn fmt(
686 &self,
687 f: &mut std::fmt::Formatter<'_>,
688 db: &(dyn SemanticGroup + 'static),
689 ) -> std::fmt::Result {
690 write!(f, "{}", self.generic_function.format(db))?;
691 fmt_generic_args(&self.generic_args, f, db)
692 }
693}
694
695#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, SemanticObject)]
696#[debug_db(dyn SemanticGroup + 'static)]
697pub struct Signature {
698 pub params: Vec<semantic::Parameter>,
699 pub return_type: semantic::TypeId,
700 pub implicits: Vec<semantic::TypeId>,
702 #[dont_rewrite]
703 pub panicable: bool,
704 #[dont_rewrite]
705 pub is_const: bool,
706 #[hide_field_debug_with_db]
707 #[dont_rewrite]
708 pub stable_ptr: ast::FunctionSignaturePtr,
709}
710
711impl Signature {
712 pub fn from_ast(
713 diagnostics: &mut SemanticDiagnostics,
714 db: &dyn SemanticGroup,
715 resolver: &mut Resolver<'_>,
716 declaration_syntax: &ast::FunctionDeclaration,
717 function_title_id: FunctionTitleId,
718 environment: &mut Environment,
719 ) -> Self {
720 let signature_syntax = declaration_syntax.signature(db);
721 let params = function_signature_params(
722 diagnostics,
723 db,
724 resolver,
725 &signature_syntax.parameters(db).elements(db),
726 Some(function_title_id),
727 environment,
728 );
729 let return_type =
730 function_signature_return_type(diagnostics, db, resolver, &signature_syntax);
731 let implicits =
732 function_signature_implicit_parameters(diagnostics, db, resolver, &signature_syntax);
733 let panicable = match signature_syntax.optional_no_panic(db) {
734 ast::OptionTerminalNoPanic::Empty(_) => true,
735 ast::OptionTerminalNoPanic::TerminalNoPanic(_) => false,
736 };
737 let stable_ptr = signature_syntax.stable_ptr(db);
738 let is_const = matches!(
739 declaration_syntax.optional_const(db),
740 ast::OptionTerminalConst::TerminalConst(_)
741 );
742 semantic::Signature { params, return_type, implicits, panicable, stable_ptr, is_const }
743 }
744}
745
746pub fn function_signature_return_type(
747 diagnostics: &mut SemanticDiagnostics,
748 db: &dyn SemanticGroup,
749 resolver: &mut Resolver<'_>,
750 sig: &ast::FunctionSignature,
751) -> semantic::TypeId {
752 let ty_syntax = match sig.ret_ty(db) {
753 ast::OptionReturnTypeClause::Empty(_) => {
754 return unit_ty(db);
755 }
756 ast::OptionReturnTypeClause::ReturnTypeClause(ret_type_clause) => ret_type_clause.ty(db),
757 };
758 resolve_type(db, diagnostics, resolver, &ty_syntax)
759}
760
761pub fn function_signature_implicit_parameters(
763 diagnostics: &mut SemanticDiagnostics,
764 db: &dyn SemanticGroup,
765 resolver: &mut Resolver<'_>,
766 sig: &ast::FunctionSignature,
767) -> Vec<semantic::TypeId> {
768 let ast_implicits = match sig.implicits_clause(db) {
769 ast::OptionImplicitsClause::Empty(_) => Vec::new(),
770 ast::OptionImplicitsClause::ImplicitsClause(implicits_clause) => {
771 implicits_clause.implicits(db).elements(db)
772 }
773 };
774
775 let mut implicits = Vec::new();
776 for implicit in ast_implicits {
777 implicits.push(resolve_type(
778 db,
779 diagnostics,
780 resolver,
781 &syntax::node::ast::Expr::Path(implicit),
782 ));
783 }
784 implicits
785}
786
787pub fn function_signature_params(
789 diagnostics: &mut SemanticDiagnostics,
790 db: &dyn SemanticGroup,
791 resolver: &mut Resolver<'_>,
792 params: &[ast::Param],
793 function_title_id: Option<FunctionTitleId>,
794 env: &mut Environment,
795) -> Vec<semantic::Parameter> {
796 update_env_with_ast_params(diagnostics, db, resolver, params, function_title_id, env)
797}
798
799pub fn function_title_signature(
801 db: &dyn SemanticGroup,
802 function_title_id: FunctionTitleId,
803) -> Maybe<Signature> {
804 match function_title_id {
805 FunctionTitleId::Free(free_function) => db.free_function_signature(free_function),
806 FunctionTitleId::Extern(extern_function) => db.extern_function_signature(extern_function),
807 FunctionTitleId::Trait(trait_function) => db.trait_function_signature(trait_function),
808 FunctionTitleId::Impl(impl_function) => db.impl_function_signature(impl_function),
809 }
810}
811pub fn function_title_generic_params(
813 db: &dyn SemanticGroup,
814 function_title_id: FunctionTitleId,
815) -> Maybe<Vec<semantic::GenericParam>> {
816 match function_title_id {
817 FunctionTitleId::Free(free_function) => db.free_function_generic_params(free_function),
818 FunctionTitleId::Extern(extern_function) => {
819 db.extern_function_declaration_generic_params(extern_function)
820 }
821 FunctionTitleId::Trait(trait_function) => db.trait_function_generic_params(trait_function),
822 FunctionTitleId::Impl(impl_function) => db.impl_function_generic_params(impl_function),
823 }
824}
825
826pub fn concrete_function_signature(
828 db: &dyn SemanticGroup,
829 function_id: FunctionId,
830) -> Maybe<Signature> {
831 let ConcreteFunction { generic_function, generic_args, .. } =
832 function_id.lookup_intern(db).function;
833 let generic_params = generic_function.generic_params(db)?;
834 let generic_signature = generic_function.generic_signature(db)?;
835 GenericSubstitution::new(&generic_params, &generic_args).substitute(db, generic_signature)
839}
840
841pub fn concrete_function_closure_params(
843 db: &dyn SemanticGroup,
844 function_id: FunctionId,
845) -> Maybe<OrderedHashMap<semantic::TypeId, semantic::TypeId>> {
846 let ConcreteFunction { generic_function, generic_args, .. } =
847 function_id.lookup_intern(db).function;
848 let generic_params = generic_function.generic_params(db)?;
849 let mut generic_closure_params = db.get_closure_params(generic_function)?;
850 let substitution = GenericSubstitution::new(&generic_params, &generic_args);
851 let mut changed_keys = vec![];
852 for (key, value) in generic_closure_params.iter_mut() {
853 *value = substitution.substitute(db, *value)?;
854 let updated_key = substitution.substitute(db, *key)?;
855 if updated_key != *key {
856 changed_keys.push((*key, updated_key));
857 }
858 }
859 for (old_key, new_key) in changed_keys {
860 let v = generic_closure_params.swap_remove(&old_key).unwrap();
861 generic_closure_params.insert(new_key, v);
862 }
863 Ok(generic_closure_params)
864}
865
866fn update_env_with_ast_params(
869 diagnostics: &mut SemanticDiagnostics,
870 db: &dyn SemanticGroup,
871 resolver: &mut Resolver<'_>,
872 ast_params: &[ast::Param],
873 function_title_id: Option<FunctionTitleId>,
874 env: &mut Environment,
875) -> Vec<semantic::Parameter> {
876 let mut semantic_params = Vec::new();
877 for ast_param in ast_params {
878 let semantic_param = ast_param_to_semantic(diagnostics, db, resolver, ast_param);
879
880 if env
881 .add_param(db, diagnostics, semantic_param.clone(), ast_param, function_title_id)
882 .is_ok()
883 {
884 semantic_params.push(semantic_param);
885 }
886 }
887 semantic_params
888}
889
890fn ast_param_to_semantic(
892 diagnostics: &mut SemanticDiagnostics,
893 db: &dyn SemanticGroup,
894 resolver: &mut Resolver<'_>,
895 ast_param: &ast::Param,
896) -> semantic::Parameter {
897 let name = ast_param.name(db).text(db);
898
899 let id = ParamLongId(resolver.module_file_id, ast_param.stable_ptr(db)).intern(db);
900
901 let ty = match ast_param.type_clause(db) {
902 ast::OptionTypeClause::Empty(missing) => {
903 resolver.inference().new_type_var(Some(missing.stable_ptr(db).untyped()))
904 }
905 ast::OptionTypeClause::TypeClause(ty_syntax) => {
906 resolve_type(db, diagnostics, resolver, &ty_syntax.ty(db))
907 }
908 };
909
910 let mutability =
911 modifiers::compute_mutability(diagnostics, db, &ast_param.modifiers(db).elements(db));
912
913 semantic::Parameter { id, name, ty, mutability, stable_ptr: ast_param.name(db).stable_ptr(db) }
914}
915
916#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
919#[debug_db(dyn SemanticGroup + 'static)]
920pub struct FunctionDeclarationData {
921 pub diagnostics: Diagnostics<SemanticDiagnostic>,
922 pub signature: semantic::Signature,
923 pub environment: Environment,
925 pub generic_params: Vec<semantic::GenericParam>,
926 pub attributes: Vec<Attribute>,
927 pub resolver_data: Arc<ResolverData>,
928 pub inline_config: InlineConfiguration,
929 pub implicit_precedence: ImplicitPrecedence,
933}
934
935#[derive(Debug, PartialEq, Eq, Clone)]
936pub enum InlineConfiguration {
937 None,
939 Always(Attribute),
940 Should(Attribute),
941 Never(Attribute),
942}
943
944pub fn forbid_inline_always_with_impl_generic_param(
946 diagnostics: &mut SemanticDiagnostics,
947 generic_params: &[GenericParam],
948 inline_config: &InlineConfiguration,
949) {
950 let has_impl_generic_param = generic_params.iter().any(|p| matches!(p, GenericParam::Impl(_)));
951 match &inline_config {
952 InlineConfiguration::Always(attr) if has_impl_generic_param => {
953 diagnostics.report(
954 attr.stable_ptr.untyped(),
955 SemanticDiagnosticKind::InlineAlwaysWithImplGenericArgNotAllowed,
956 );
957 }
958 _ => {}
959 }
960}
961
962#[derive(Clone, Debug, Default, Eq, PartialEq)]
981pub struct ImplicitPrecedence(Vec<TypeId>);
982
983impl ImplicitPrecedence {
984 pub const UNSPECIFIED: Self = Self(Vec::new());
988
989 pub fn apply(&self, implicits: &mut [TypeId], db: &dyn SemanticGroup) {
992 implicits.sort_by_cached_key(|implicit| {
993 if let Some(idx) = self.0.iter().position(|item| item == implicit) {
994 return (idx, "".to_string());
995 }
996
997 (self.0.len(), implicit.format(db))
998 });
999 }
1000}
1001
1002impl FromIterator<TypeId> for ImplicitPrecedence {
1003 fn from_iter<T: IntoIterator<Item = TypeId>>(iter: T) -> Self {
1004 Self(Vec::from_iter(iter))
1005 }
1006}
1007
1008pub fn get_closure_params(
1010 db: &dyn SemanticGroup,
1011 generic_function_id: GenericFunctionId,
1012) -> Maybe<OrderedHashMap<TypeId, TypeId>> {
1013 let mut closure_params_map = OrderedHashMap::default();
1014 let generic_params = generic_function_id.generic_params(db)?;
1015
1016 for param in generic_params {
1017 if let GenericParam::Impl(generic_param_impl) = param {
1018 let trait_id = generic_param_impl.concrete_trait?.trait_id(db);
1019
1020 if fn_traits(db).contains(&trait_id) {
1021 if let Ok(concrete_trait) = generic_param_impl.concrete_trait {
1022 let [
1023 GenericArgumentId::Type(closure_type),
1024 GenericArgumentId::Type(params_type),
1025 ] = *concrete_trait.generic_args(db)
1026 else {
1027 unreachable!(
1028 "Fn trait must have exactly two generic arguments: closure type and \
1029 parameter type."
1030 )
1031 };
1032
1033 closure_params_map.insert(closure_type, params_type);
1034 }
1035 }
1036 }
1037 }
1038 Ok(closure_params_map)
1039}