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