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