1use std::fmt::Write;
2use std::hash::Hash;
3use std::sync::Arc;
4
5use cairo_lang_debug::DebugWithDb;
6use cairo_lang_defs::ids::{
7 GenericItemId, GenericKind, GenericModuleItemId, GenericParamId, GenericParamLongId,
8 LanguageElementId, LookupItemId, ModuleId, TraitId, TraitTypeId,
9};
10use cairo_lang_diagnostics::{Diagnostics, Maybe, MaybeAsRef, skip_diagnostic};
11use cairo_lang_filesystem::db::FilesGroup;
12use cairo_lang_filesystem::ids::Tracked;
13use cairo_lang_proc_macros::{DebugWithDb, HeapSize, SemanticObject};
14use cairo_lang_syntax as syntax;
15use cairo_lang_syntax::node::ast::{AssociatedItemConstraints, OptionAssociatedItemConstraints};
16use cairo_lang_syntax::node::{Terminal, TypedSyntaxNode, ast};
17use cairo_lang_utils::ordered_hash_map::{Entry, OrderedHashMap};
18use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
19use cairo_lang_utils::{Intern, extract_matches};
20use salsa::Database;
21use syntax::node::TypedStablePtr;
22
23use super::constant::{ConstValue, ConstValueId};
24use super::imp::{ImplHead, ImplId, ImplLongId, NegativeImplId};
25use super::resolve_trait_path;
26use super::trt::ConcreteTraitTypeId;
27use crate::corelib::CorelibSemantic;
28use crate::diagnostic::{
29 NotFoundItemType, SemanticDiagnosticKind, SemanticDiagnostics, SemanticDiagnosticsBuilder,
30};
31use crate::expr::fmt::CountingWriter;
32use crate::expr::inference::InferenceId;
33use crate::expr::inference::canonic::ResultNoErrEx;
34use crate::items::imp::NegativeImplLongId;
35use crate::items::trt::TraitSemantic;
36use crate::lookup_item::LookupItemEx;
37use crate::resolve::{
38 ResolutionContext, ResolvedConcreteItem, ResolvedGenericItem, Resolver, ResolverData,
39};
40use crate::substitution::SemanticRewriter;
41use crate::types::{
42 ImplTypeId, ShallowGenericArg, TypeHead, maybe_resolve_shallow_generic_arg_type, resolve_type,
43};
44use crate::{ConcreteTraitId, ConcreteTraitLongId, SemanticDiagnostic, TypeId, TypeLongId};
45
46#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, SemanticObject, salsa::Update, HeapSize)]
50pub enum GenericArgumentId<'db> {
51 Type(TypeId<'db>),
52 Constant(ConstValueId<'db>),
53 Impl(ImplId<'db>),
54 NegImpl(NegativeImplId<'db>),
55}
56impl<'db> GenericArgumentId<'db> {
57 pub fn kind(&self) -> GenericKind {
58 match self {
59 GenericArgumentId::Type(_) => GenericKind::Type,
60 GenericArgumentId::Constant(_) => GenericKind::Const,
61 GenericArgumentId::Impl(_) => GenericKind::Impl,
62 GenericArgumentId::NegImpl(_) => GenericKind::NegImpl,
63 }
64 }
65 pub fn format(&self, db: &dyn Database) -> String {
66 match self {
67 GenericArgumentId::Type(ty) => ty.format(db),
68 GenericArgumentId::Constant(value) => value.format(db),
69 GenericArgumentId::Impl(imp) => imp.format(db),
70 GenericArgumentId::NegImpl(_) => "_".into(),
71 }
72 }
73 pub fn head(&self, db: &'db dyn Database) -> Option<GenericArgumentHead<'db>> {
75 Some(match self {
76 GenericArgumentId::Type(ty) => GenericArgumentHead::Type(ty.head(db)?),
77 GenericArgumentId::Constant(_) => GenericArgumentHead::Const,
78 GenericArgumentId::Impl(impl_id) => GenericArgumentHead::Impl(impl_id.head(db)?),
79 GenericArgumentId::NegImpl(_) => GenericArgumentHead::NegImpl,
80 })
81 }
82 pub fn is_fully_concrete(&self, db: &dyn Database) -> bool {
84 match self {
85 GenericArgumentId::Type(id) => id.is_fully_concrete(db),
86 GenericArgumentId::Constant(id) => id.is_fully_concrete(db),
87 GenericArgumentId::Impl(id) => id.is_fully_concrete(db),
88 GenericArgumentId::NegImpl(id) => id.is_fully_concrete(db),
89 }
90 }
91 pub fn is_var_free(&self, db: &dyn Database) -> bool {
93 match self {
94 GenericArgumentId::Type(id) => id.is_var_free(db),
95 GenericArgumentId::Constant(id) => id.is_var_free(db),
96 GenericArgumentId::Impl(id) => id.is_var_free(db),
97 GenericArgumentId::NegImpl(id) => id.is_var_free(db),
98 }
99 }
100 pub fn short_name(&self, db: &dyn Database) -> String {
102 if let GenericArgumentId::Type(ty) = self { ty.short_name(db) } else { self.format(db) }
103 }
104
105 pub fn extract_generic_params(
107 &self,
108 db: &'db dyn Database,
109 generic_parameters: &mut OrderedHashSet<GenericParamId<'db>>,
110 ) -> Maybe<()> {
111 match self {
112 GenericArgumentId::Type(ty) => {
113 ty.long(db).extract_generic_params(db, generic_parameters)?
114 }
115 GenericArgumentId::Constant(const_value_id) => {
116 const_value_id.ty(db)?.long(db).extract_generic_params(db, generic_parameters)?
117 }
118 GenericArgumentId::Impl(impl_id) => {
119 for garg in impl_id.concrete_trait(db)?.generic_args(db) {
120 garg.extract_generic_params(db, generic_parameters)?;
121 }
122 }
123 GenericArgumentId::NegImpl(negative_impl_id) => {
124 for garg in negative_impl_id.concrete_trait(db)?.generic_args(db) {
125 garg.extract_generic_params(db, generic_parameters)?;
126 }
127 }
128 }
129
130 Ok(())
131 }
132}
133impl<'db> DebugWithDb<'db> for GenericArgumentId<'db> {
134 type Db = dyn Database;
135
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
137 match self {
138 GenericArgumentId::Type(id) => write!(f, "{:?}", id.debug(db)),
139 GenericArgumentId::Constant(id) => write!(f, "{:?}", id.debug(db)),
140 GenericArgumentId::Impl(id) => write!(f, "{:?}", id.debug(db)),
141 GenericArgumentId::NegImpl(_) => write!(f, "_"),
142 }
143 }
144}
145
146#[derive(Clone, Debug, Hash, PartialEq, Eq, salsa::Update)]
152pub enum GenericArgumentHead<'db> {
153 Type(TypeHead<'db>),
154 Impl(ImplHead<'db>),
155 Const,
156 NegImpl,
157}
158
159#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject, HeapSize, salsa::Update)]
161pub enum GenericParam<'db> {
162 Type(GenericParamType<'db>),
163 Const(GenericParamConst<'db>),
165 Impl(GenericParamImpl<'db>),
166 NegImpl(GenericParamImpl<'db>),
167}
168impl<'db> GenericParam<'db> {
169 pub fn id(&self) -> GenericParamId<'db> {
170 match self {
171 GenericParam::Type(param) => param.id,
172 GenericParam::Const(param) => param.id,
173 GenericParam::Impl(param) => param.id,
174 GenericParam::NegImpl(param) => param.id,
175 }
176 }
177 pub fn kind(&self) -> GenericKind {
178 match self {
179 GenericParam::Type(_) => GenericKind::Type,
180 GenericParam::Const(_) => GenericKind::Const,
181 GenericParam::Impl(_) => GenericKind::Impl,
182 GenericParam::NegImpl(_) => GenericKind::NegImpl,
183 }
184 }
185 pub fn stable_ptr(&self, db: &'db dyn Database) -> ast::GenericParamPtr<'db> {
186 self.id().stable_ptr(db)
187 }
188 pub fn as_arg(&self, db: &'db dyn Database) -> GenericArgumentId<'db> {
190 match self {
191 GenericParam::Type(param_type) => {
192 GenericArgumentId::Type(TypeLongId::GenericParameter(param_type.id).intern(db))
193 }
194 GenericParam::Const(param_const) => {
195 GenericArgumentId::Constant(ConstValue::Generic(param_const.id).intern(db))
196 }
197 GenericParam::Impl(param_impl) => {
198 GenericArgumentId::Impl(ImplLongId::GenericParameter(param_impl.id).intern(db))
199 }
200 GenericParam::NegImpl(param_neg_impl) => GenericArgumentId::NegImpl(
201 NegativeImplLongId::GenericParameter(param_neg_impl.id).intern(db),
202 ),
203 }
204 }
205}
206impl<'db> DebugWithDb<'db> for GenericParam<'db> {
207 type Db = dyn Database;
208
209 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
210 write!(f, "{:?}", self.id().debug(db))
211 }
212}
213
214pub fn generic_params_to_args<'db>(
216 params: &[GenericParam<'db>],
217 db: &'db dyn Database,
218) -> Vec<GenericArgumentId<'db>> {
219 params.iter().map(|param| param.as_arg(db)).collect()
220}
221
222#[derive(
223 Copy, Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject, HeapSize, salsa::Update,
224)]
225#[debug_db(dyn Database)]
226pub struct GenericParamType<'db> {
227 pub id: GenericParamId<'db>,
228}
229#[derive(
230 Copy, Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject, HeapSize, salsa::Update,
231)]
232#[debug_db(dyn Database)]
233pub struct GenericParamConst<'db> {
234 pub id: GenericParamId<'db>,
235 pub ty: TypeId<'db>,
236}
237#[derive(
238 Clone, Debug, PartialEq, Eq, Hash, DebugWithDb, SemanticObject, HeapSize, salsa::Update,
239)]
240#[debug_db(dyn Database)]
241pub struct GenericParamImpl<'db> {
242 pub id: GenericParamId<'db>,
243 pub concrete_trait: Maybe<ConcreteTraitId<'db>>,
244 pub type_constraints: OrderedHashMap<TraitTypeId<'db>, TypeId<'db>>,
245}
246
247#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, salsa::Update)]
249#[debug_db(dyn Database)]
250pub struct GenericParamData<'db> {
251 pub generic_param: Maybe<GenericParam<'db>>,
252 pub diagnostics: Diagnostics<'db, SemanticDiagnostic<'db>>,
253 pub resolver_data: Arc<ResolverData<'db>>,
254}
255
256#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, salsa::Update)]
258#[debug_db(dyn Database)]
259pub struct GenericParamsData<'db> {
260 pub generic_params: Vec<GenericParam<'db>>,
261 pub diagnostics: Diagnostics<'db, SemanticDiagnostic<'db>>,
262 pub resolver_data: Arc<ResolverData<'db>>,
263}
264
265#[salsa::tracked]
267fn generic_impl_param_trait<'db>(
268 db: &'db dyn Database,
269 generic_param_id: GenericParamId<'db>,
270) -> Maybe<TraitId<'db>> {
271 let module_id = generic_param_id.parent_module(db);
272 let option_generic_params_syntax = generic_param_generic_params_list(db, generic_param_id)?;
273 let generic_params_syntax = extract_matches!(
274 option_generic_params_syntax,
275 ast::OptionWrappedGenericParamList::WrappedGenericParamList
276 );
277 let generic_param_syntax = generic_params_syntax
278 .generic_params(db)
279 .elements(db)
280 .find(|param_syntax| {
281 GenericParamLongId(module_id, param_syntax.stable_ptr(db)).intern(db)
282 == generic_param_id
283 })
284 .unwrap();
285
286 let trait_path_syntax = match generic_param_syntax {
287 ast::GenericParam::ImplNamed(syntax) => syntax.trait_path(db),
288 ast::GenericParam::ImplAnonymous(syntax) => syntax.trait_path(db),
289 _ => {
290 panic!("generic_impl_param_trait() called on a non impl generic param.")
291 }
292 };
293
294 let mut diagnostics = SemanticDiagnostics::default();
295 let inference_id = InferenceId::GenericImplParamTrait(generic_param_id);
296 let mut resolver = Resolver::new(db, module_id, inference_id);
300
301 resolve_trait_path(db, &mut diagnostics, &mut resolver, &trait_path_syntax)
302}
303
304#[salsa::tracked(returns(ref))]
307fn generic_impl_param_shallow_trait_generic_args<'db>(
308 db: &'db dyn Database,
309 generic_param_id: GenericParamId<'db>,
310) -> Maybe<Vec<(GenericParamId<'db>, ShallowGenericArg<'db>)>> {
311 let db: &dyn Database = db;
312 let module_id = generic_param_id.parent_module(db);
313 let mut diagnostics: cairo_lang_diagnostics::DiagnosticsBuilder<'_, SemanticDiagnostic<'_>> =
314 SemanticDiagnostics::default();
315 let parent_item_id = generic_param_id.generic_item(db);
316 let lookup_item: LookupItemId<'_> = parent_item_id.into();
317 let context_resolver_data = lookup_item.resolver_context(db)?;
318 let inference_id = InferenceId::GenericParam(generic_param_id);
319 let mut resolver =
320 Resolver::with_data(db, (*context_resolver_data).clone_with_inference_id(db, inference_id));
321 resolver.set_feature_config(
322 &lookup_item,
323 &lookup_item.untyped_stable_ptr(db).lookup(db),
324 &mut diagnostics,
325 );
326 let generic_params_syntax = extract_matches!(
327 generic_param_generic_params_list(db, generic_param_id)?,
328 ast::OptionWrappedGenericParamList::WrappedGenericParamList
329 );
330
331 let mut opt_generic_param_syntax = None;
332 for param_syntax in generic_params_syntax.generic_params(db).elements(db) {
333 let cur_generic_param_id =
334 GenericParamLongId(module_id, param_syntax.stable_ptr(db)).intern(db);
335 resolver.add_generic_param(cur_generic_param_id);
336
337 if cur_generic_param_id == generic_param_id {
338 opt_generic_param_syntax = Some(param_syntax);
339 break;
340 }
341 }
342
343 let generic_param_syntax =
344 opt_generic_param_syntax.expect("Query called on a non existing generic param.");
345
346 let trait_path_syntax = match generic_param_syntax {
347 ast::GenericParam::ImplNamed(syntax) => syntax.trait_path(db),
348 ast::GenericParam::ImplAnonymous(syntax) => syntax.trait_path(db),
349 ast::GenericParam::NegativeImpl(syntax) => syntax.trait_path(db),
350 _ => {
351 unreachable!(
352 "generic_impl_param_shallow_trait_generic_args called on a non impl generic param."
353 )
354 }
355 };
356
357 let ResolvedGenericItem::Trait(trait_id) = resolver.resolve_generic_path_with_args(
358 &mut diagnostics,
359 &trait_path_syntax,
360 NotFoundItemType::Trait,
361 ResolutionContext::Default,
362 )?
363 else {
364 return Err(skip_diagnostic());
365 };
366 let generic_params = db
367 .trait_generic_params_ids(trait_id)?
368 .iter()
369 .map(|param_syntax| {
370 GenericParamLongId(trait_id.parent_module(db), param_syntax.stable_ptr(db)).intern(db)
371 })
372 .collect::<Vec<_>>();
373
374 let elements = trait_path_syntax.segments(db).elements(db);
375 let Some(last) = elements.last() else {
376 return Ok(Vec::new());
377 };
378
379 match last {
380 ast::PathSegment::Simple(_) => Ok(Vec::new()),
381 ast::PathSegment::WithGenericArgs(path_segment_with_generic_args) => {
382 let generic_args =
383 path_segment_with_generic_args.generic_args(db).generic_args(db).elements_vec(db);
384
385 let arg_syntax_per_param = resolver.get_arg_syntax_per_param(
386 &mut diagnostics,
387 &generic_params,
388 &generic_args,
389 )?;
390 Ok(generic_params
391 .iter()
392 .filter_map(|generic_param| {
393 let expr = arg_syntax_per_param.get(generic_param)?;
394 let x = maybe_resolve_shallow_generic_arg_type(
395 db,
396 &mut diagnostics,
397 &mut resolver,
398 expr,
399 )?;
400 Some((*generic_param, x))
401 })
402 .collect::<Vec<_>>())
403 }
404 ast::PathSegment::Missing(_) => Ok(Vec::new()),
405 }
406}
407
408#[salsa::tracked(cycle_result=generic_param_data_cycle, returns(ref))]
410fn generic_param_data<'db>(
411 db: &'db dyn Database,
412 generic_param_id: GenericParamId<'db>,
413 in_cycle: bool,
414) -> Maybe<GenericParamData<'db>> {
415 if in_cycle {
416 let mut diagnostics = SemanticDiagnostics::default();
417 return Ok(GenericParamData {
418 generic_param: Err(diagnostics.report(
419 generic_param_id.stable_ptr(db).untyped(),
420 SemanticDiagnosticKind::ImplRequirementCycle,
421 )),
422 diagnostics: diagnostics.build(),
423 resolver_data: Arc::new(ResolverData::new(
424 generic_param_id.parent_module(db),
425 InferenceId::GenericParam(generic_param_id),
426 )),
427 });
428 }
429 let module_id = generic_param_id.parent_module(db);
430 let mut diagnostics = SemanticDiagnostics::default();
431 let parent_item_id = generic_param_id.generic_item(db);
432 let lookup_item: LookupItemId<'_> = parent_item_id.into();
433 let context_resolver_data = lookup_item.resolver_context(db)?;
434 let inference_id = InferenceId::GenericParam(generic_param_id);
435 let mut resolver =
436 Resolver::with_data(db, (*context_resolver_data).clone_with_inference_id(db, inference_id));
437 resolver.set_feature_config(
438 &lookup_item,
439 &lookup_item.untyped_stable_ptr(db).lookup(db),
440 &mut diagnostics,
441 );
442 let generic_params_syntax = extract_matches!(
443 generic_param_generic_params_list(db, generic_param_id)?,
444 ast::OptionWrappedGenericParamList::WrappedGenericParamList
445 );
446
447 let mut opt_generic_param_syntax = None;
448 for param_syntax in generic_params_syntax.generic_params(db).elements(db) {
449 let cur_generic_param_id =
450 GenericParamLongId(module_id, param_syntax.stable_ptr(db)).intern(db);
451 resolver.add_generic_param(cur_generic_param_id);
452
453 if cur_generic_param_id == generic_param_id {
454 opt_generic_param_syntax = Some(param_syntax);
455 }
456 }
457 let generic_param_syntax =
458 opt_generic_param_syntax.expect("Query called on a non existing generic param.");
459 let param_semantic = semantic_from_generic_param_ast(
460 db,
461 &mut resolver,
462 &mut diagnostics,
463 module_id,
464 &generic_param_syntax,
465 parent_item_id,
466 )?;
467 let inference = &mut resolver.inference();
468 inference.finalize(&mut diagnostics, generic_param_syntax.stable_ptr(db).untyped());
469
470 let param_semantic = inference.rewrite(param_semantic).no_err();
471 let resolver_data = Arc::new(resolver.data);
472 Ok(GenericParamData {
473 generic_param: Ok(param_semantic),
474 diagnostics: diagnostics.build(),
475 resolver_data,
476 })
477}
478
479fn generic_param_data_cycle<'db>(
481 db: &'db dyn Database,
482 generic_param_id: GenericParamId<'db>,
483 _in_cycle: bool,
484) -> Maybe<GenericParamData<'db>> {
485 generic_param_data(db, generic_param_id, true).clone()
486}
487
488#[salsa::tracked(returns(ref))]
490fn generic_params_type_constraints<'db>(
491 db: &'db dyn Database,
492 _tracked: Tracked,
493 generic_params: Vec<GenericParamId<'db>>,
494) -> Vec<(TypeId<'db>, TypeId<'db>)> {
495 let mut constraints = vec![];
496 for param in &generic_params {
497 let Ok(GenericParam::Impl(imp)) = db.generic_param_semantic(*param) else {
498 continue;
499 };
500 let Ok(concrete_trait_id) = imp.concrete_trait else {
501 continue;
502 };
503 for (trait_ty, ty1) in imp.type_constraints {
504 let impl_type = TypeLongId::ImplType(ImplTypeId::new(
505 ImplLongId::GenericParameter(*param).intern(db),
506 trait_ty,
507 db,
508 ))
509 .intern(db);
510 constraints.push((impl_type, ty1));
511 }
512 let ConcreteTraitLongId { trait_id, generic_args } = concrete_trait_id.long(db);
513 if trait_id != &db.core_info().type_eq_trt {
514 continue;
515 }
516 let [GenericArgumentId::Type(ty0), GenericArgumentId::Type(ty1)] = generic_args.as_slice()
517 else {
518 unreachable!("TypeEqual should have 2 arguments");
519 };
520 constraints.push((*ty0, *ty1));
521 }
522 constraints
523}
524
525fn generic_param_generic_params_list<'db>(
529 db: &'db dyn Database,
530 generic_param_id: GenericParamId<'db>,
531) -> Maybe<ast::OptionWrappedGenericParamList<'db>> {
532 let generic_param_long_id = generic_param_id.long(db);
533
534 let wrapped_generic_param_list = generic_param_long_id.1.0.nth_parent(db, 2);
536
537 Ok(ast::OptionWrappedGenericParamListPtr(wrapped_generic_param_list).lookup(db))
538}
539
540pub fn semantic_generic_params<'db>(
543 db: &'db dyn Database,
544 diagnostics: &mut SemanticDiagnostics<'db>,
545 resolver: &mut Resolver<'db>,
546 module_id: ModuleId<'db>,
547 generic_params: &ast::OptionWrappedGenericParamList<'db>,
548) -> Vec<GenericParam<'db>> {
549 semantic_generic_params_ex(db, diagnostics, resolver, module_id, generic_params, false)
550}
551
552pub fn semantic_generic_params_ex<'db>(
553 db: &'db dyn Database,
554 diagnostics: &mut SemanticDiagnostics<'db>,
555 resolver: &mut Resolver<'db>,
556 module_id: ModuleId<'db>,
557 generic_params: &ast::OptionWrappedGenericParamList<'db>,
558 in_cycle: bool,
559) -> Vec<GenericParam<'db>> {
560 match generic_params {
561 syntax::node::ast::OptionWrappedGenericParamList::Empty(_) => vec![],
562 syntax::node::ast::OptionWrappedGenericParamList::WrappedGenericParamList(syntax) => syntax
563 .generic_params(db)
564 .elements(db)
565 .filter_map(|param_syntax| {
566 let generic_param_id =
567 GenericParamLongId(module_id, param_syntax.stable_ptr(db)).intern(db);
568 let data = generic_param_data(db, generic_param_id, in_cycle).as_ref().ok()?;
569 let generic_param = data.generic_param.clone();
570 diagnostics.extend(data.diagnostics.clone());
571 resolver.add_generic_param(generic_param_id);
572 resolver.data.used_uses.extend(data.resolver_data.used_uses.iter().copied());
573 generic_param.ok()
574 })
575 .collect(),
576 }
577}
578
579fn are_negative_impls_enabled<'db>(db: &dyn Database, module_id: ModuleId<'db>) -> bool {
581 let owning_crate = module_id.owning_crate(db);
582 let Some(config) = db.crate_config(owning_crate) else { return false };
583 config.settings.experimental_features.negative_impls
584}
585
586fn is_associated_item_constraints_enabled(db: &dyn Database, module_id: ModuleId<'_>) -> bool {
588 let owning_crate = module_id.owning_crate(db);
589 db.crate_config(owning_crate)
590 .is_some_and(|c| c.settings.experimental_features.associated_item_constraints)
591}
592
593fn semantic_from_generic_param_ast<'db>(
595 db: &'db dyn Database,
596 resolver: &mut Resolver<'db>,
597 diagnostics: &mut SemanticDiagnostics<'db>,
598 module_id: ModuleId<'db>,
599 param_syntax: &ast::GenericParam<'db>,
600 parent_item_id: GenericItemId<'db>,
601) -> Maybe<GenericParam<'db>> {
602 let id = GenericParamLongId(module_id, param_syntax.stable_ptr(db)).intern(db);
603 let mut item_constraints_into_option = |constraint| match constraint {
604 OptionAssociatedItemConstraints::Empty(_) => None,
605 OptionAssociatedItemConstraints::AssociatedItemConstraints(associated_type_args) => {
606 if !is_associated_item_constraints_enabled(db, module_id) {
607 diagnostics.report(
608 associated_type_args.stable_ptr(db),
609 SemanticDiagnosticKind::TypeConstraintsSyntaxNotEnabled,
610 );
611 }
612 Some(associated_type_args)
613 }
614 };
615 Ok(match param_syntax {
616 ast::GenericParam::Type(_) => GenericParam::Type(GenericParamType { id }),
617 ast::GenericParam::Const(syntax) => {
618 let ty = resolve_type(db, diagnostics, resolver, &syntax.ty(db));
619 GenericParam::Const(GenericParamConst { id, ty })
620 }
621 ast::GenericParam::ImplNamed(syntax) => {
622 let path_syntax = syntax.trait_path(db);
623 let item_constrains = item_constraints_into_option(syntax.type_constrains(db));
624 GenericParam::Impl(impl_generic_param_semantic(
625 db,
626 resolver,
627 diagnostics,
628 &path_syntax,
629 item_constrains,
630 id,
631 ))
632 }
633 ast::GenericParam::ImplAnonymous(syntax) => {
634 let path_syntax = syntax.trait_path(db);
635 let item_constrains = item_constraints_into_option(syntax.type_constrains(db));
636 GenericParam::Impl(impl_generic_param_semantic(
637 db,
638 resolver,
639 diagnostics,
640 &path_syntax,
641 item_constrains,
642 id,
643 ))
644 }
645 ast::GenericParam::NegativeImpl(syntax) => {
646 if !are_negative_impls_enabled(db, module_id) {
647 diagnostics.report(
648 param_syntax.stable_ptr(db),
649 SemanticDiagnosticKind::NegativeImplsNotEnabled,
650 );
651 }
652
653 if !matches!(parent_item_id, GenericItemId::ModuleItem(GenericModuleItemId::Impl(_))) {
654 diagnostics.report(
655 param_syntax.stable_ptr(db),
656 SemanticDiagnosticKind::NegativeImplsOnlyOnImpls,
657 );
658 }
659
660 let path_syntax = syntax.trait_path(db);
661
662 let neg_impl =
663 impl_generic_param_semantic(db, resolver, diagnostics, &path_syntax, None, id);
664 for param in db.trait_generic_params(neg_impl.concrete_trait?.trait_id(db))? {
665 if matches!(param, GenericParam::Type(_) | GenericParam::Const(_)) {
666 continue;
667 }
668 diagnostics.report(
669 param.stable_ptr(db),
670 SemanticDiagnosticKind::OnlyTypeOrConstParamsInNegImpl,
671 );
672 }
673
674 GenericParam::NegImpl(neg_impl)
675 }
676 })
677}
678
679fn impl_generic_param_semantic<'db>(
681 db: &'db dyn Database,
682 resolver: &mut Resolver<'db>,
683 diagnostics: &mut SemanticDiagnostics<'db>,
684 path_syntax: &ast::ExprPath<'db>,
685 item_constraints: Option<AssociatedItemConstraints<'db>>,
686 id: GenericParamId<'db>,
687) -> GenericParamImpl<'db> {
688 let concrete_trait = resolver
689 .resolve_concrete_path(diagnostics, path_syntax, NotFoundItemType::Trait)
690 .and_then(|resolved_item| match resolved_item {
691 ResolvedConcreteItem::Trait(id) | ResolvedConcreteItem::SelfTrait(id) => Ok(id),
692 _ => Err(diagnostics
693 .report(path_syntax.stable_ptr(db), SemanticDiagnosticKind::UnknownTrait)),
694 });
695 let type_constraints = concrete_trait
696 .ok()
697 .and_then(|concrete_trait| {
698 item_constraints.map(|type_constraints| (concrete_trait, type_constraints))
699 })
700 .map(|(concrete_trait_id, constraints)| {
701 let mut map = OrderedHashMap::default();
702
703 for constraint in constraints.associated_item_constraints(db).elements(db) {
704 let Ok(trait_type_id_opt) = db.trait_type_by_name(
705 concrete_trait_id.trait_id(db),
706 constraint.item(db).text(db),
707 ) else {
708 continue;
709 };
710 let Some(trait_type_id) = trait_type_id_opt else {
711 diagnostics.report(
712 constraint.stable_ptr(db),
713 SemanticDiagnosticKind::NonTraitTypeConstrained {
714 identifier: constraint.item(db).text(db),
715 concrete_trait_id,
716 },
717 );
718 return map;
719 };
720
721 let concrete_trait_type_id =
722 ConcreteTraitTypeId::new_from_data(db, concrete_trait_id, trait_type_id);
723 match map.entry(trait_type_id) {
724 Entry::Vacant(entry) => {
725 entry.insert(resolve_type(
726 db,
727 diagnostics,
728 resolver,
729 &constraint.value(db),
730 ));
731 }
732 Entry::Occupied(_) => {
733 diagnostics.report(
734 path_syntax.stable_ptr(db),
735 SemanticDiagnosticKind::DuplicateTypeConstraint {
736 concrete_trait_type_id,
737 },
738 );
739 }
740 }
741 }
742 map
743 })
744 .unwrap_or_default();
745
746 GenericParamImpl { id, concrete_trait, type_constraints }
747}
748
749pub fn fmt_generic_args(
751 generic_args: &[GenericArgumentId<'_>],
752 f: &mut CountingWriter<'_, '_>,
753 db: &dyn Database,
754) -> std::fmt::Result {
755 let mut generic_args = generic_args.iter();
756 if let Some(first) = generic_args.next() {
757 const CHARS_BOUND: usize = 500;
759 write!(f, "::<")?;
760 write!(f, "{}", &first.format(db))?;
761
762 for arg in generic_args {
763 write!(f, ", ")?;
764 if f.count() > CHARS_BOUND {
765 write!(f, "{}", &arg.short_name(db))?;
767 } else {
768 write!(f, "{}", &arg.format(db))?;
769 }
770 }
771 write!(f, ">")?;
772 }
773 Ok(())
774}
775
776pub trait GenericParamSemantic<'db>: Database {
778 fn generic_param_semantic(
780 &'db self,
781 generic_param: GenericParamId<'db>,
782 ) -> Maybe<GenericParam<'db>> {
783 generic_param_data(self.as_dyn_database(), generic_param, false)
784 .maybe_as_ref()?
785 .generic_param
786 .clone()
787 }
788 fn generic_param_diagnostics(
790 &'db self,
791 generic_param: GenericParamId<'db>,
792 ) -> Diagnostics<'db, SemanticDiagnostic<'db>> {
793 generic_param_data(self.as_dyn_database(), generic_param, false)
794 .as_ref()
795 .map(|data| data.diagnostics.clone())
796 .unwrap_or_default()
797 }
798 fn generic_param_resolver_data(
800 &'db self,
801 generic_param: GenericParamId<'db>,
802 ) -> Maybe<Arc<ResolverData<'db>>> {
803 Ok(generic_param_data(self.as_dyn_database(), generic_param, false)
804 .maybe_as_ref()?
805 .resolver_data
806 .clone())
807 }
808 fn generic_impl_param_trait(
811 &'db self,
812 generic_param_id: GenericParamId<'db>,
813 ) -> Maybe<TraitId<'db>> {
814 generic_impl_param_trait(self.as_dyn_database(), generic_param_id)
815 }
816 fn generic_impl_param_shallow_trait_generic_args(
818 &'db self,
819 generic_param: GenericParamId<'db>,
820 ) -> Maybe<&'db [(GenericParamId<'db>, ShallowGenericArg<'db>)]> {
821 Ok(generic_impl_param_shallow_trait_generic_args(self.as_dyn_database(), generic_param)
822 .maybe_as_ref()?)
823 }
824 fn generic_params_type_constraints(
826 &'db self,
827 generic_params: Vec<GenericParamId<'db>>,
828 ) -> &'db [(TypeId<'db>, TypeId<'db>)] {
829 generic_params_type_constraints(self.as_dyn_database(), (), generic_params)
830 }
831}
832impl<'db, T: Database + ?Sized> GenericParamSemantic<'db> for T {}