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