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