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