1use std::hash::Hash;
2use std::sync::Arc;
3
4use cairo_lang_debug::DebugWithDb;
5use cairo_lang_defs::db::DefsGroup;
6use cairo_lang_defs::ids::{
7 GenericItemId, GenericKind, GenericModuleItemId, GenericParamId, GenericParamLongId,
8 LanguageElementId, LookupItemId, ModuleFileId, TraitId,
9};
10use cairo_lang_diagnostics::{Diagnostics, Maybe};
11use cairo_lang_proc_macros::{DebugWithDb, SemanticObject};
12use cairo_lang_syntax as syntax;
13use cairo_lang_syntax::node::ast::{AssociatedItemConstraints, OptionAssociatedItemConstraints};
14use cairo_lang_syntax::node::{Terminal, TypedSyntaxNode, ast};
15use cairo_lang_utils::ordered_hash_map::{Entry, OrderedHashMap};
16use cairo_lang_utils::{Intern, LookupIntern, extract_matches, try_extract_matches};
17use syntax::node::TypedStablePtr;
18use syntax::node::db::SyntaxGroup;
19
20use super::constant::{ConstValue, ConstValueId};
21use super::imp::{ImplHead, ImplId, ImplLongId};
22use super::resolve_trait_path;
23use super::trt::ConcreteTraitTypeId;
24use crate::corelib::{CoreTraitContext, get_core_trait};
25use crate::db::SemanticGroup;
26use crate::diagnostic::{
27 NotFoundItemType, SemanticDiagnosticKind, SemanticDiagnostics, SemanticDiagnosticsBuilder,
28};
29use crate::expr::inference::InferenceId;
30use crate::expr::inference::canonic::ResultNoErrEx;
31use crate::lookup_item::LookupItemEx;
32use crate::resolve::{ResolvedConcreteItem, Resolver, ResolverData};
33use crate::substitution::SemanticRewriter;
34use crate::types::{ImplTypeId, TypeHead, resolve_type};
35use crate::{ConcreteTraitId, ConcreteTraitLongId, SemanticDiagnostic, TypeId, TypeLongId};
36
37#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
41pub enum GenericArgumentId {
42 Type(TypeId),
43 Constant(ConstValueId),
44 Impl(ImplId),
45 NegImpl,
46}
47impl GenericArgumentId {
48 pub fn kind(&self) -> GenericKind {
49 match self {
50 GenericArgumentId::Type(_) => GenericKind::Type,
51 GenericArgumentId::Constant(_) => GenericKind::Const,
52 GenericArgumentId::Impl(_) => GenericKind::Impl,
53 GenericArgumentId::NegImpl => GenericKind::NegImpl,
54 }
55 }
56 pub fn format(&self, db: &dyn SemanticGroup) -> String {
57 match self {
58 GenericArgumentId::Type(ty) => ty.format(db),
59 GenericArgumentId::Constant(value) => value.format(db),
60 GenericArgumentId::Impl(imp) => imp.format(db),
61 GenericArgumentId::NegImpl => "_".into(),
62 }
63 }
64 pub fn head(&self, db: &dyn SemanticGroup) -> Option<GenericArgumentHead> {
66 Some(match self {
67 GenericArgumentId::Type(ty) => GenericArgumentHead::Type(ty.head(db)?),
68 GenericArgumentId::Constant(_) => GenericArgumentHead::Const,
69 GenericArgumentId::Impl(impl_id) => GenericArgumentHead::Impl(impl_id.head(db)?),
70 GenericArgumentId::NegImpl => GenericArgumentHead::NegImpl,
71 })
72 }
73 pub fn is_fully_concrete(&self, db: &dyn SemanticGroup) -> bool {
75 match self {
76 GenericArgumentId::Type(type_id) => type_id.is_fully_concrete(db),
77 GenericArgumentId::Constant(const_value_id) => const_value_id.is_fully_concrete(db),
78 GenericArgumentId::Impl(impl_id) => impl_id.is_fully_concrete(db),
79 GenericArgumentId::NegImpl => true,
80 }
81 }
82 pub fn is_var_free(&self, db: &dyn SemanticGroup) -> bool {
84 match self {
85 GenericArgumentId::Type(type_id) => type_id.is_var_free(db),
86 GenericArgumentId::Constant(const_value_id) => const_value_id.is_var_free(db),
87 GenericArgumentId::Impl(impl_id) => impl_id.is_var_free(db),
88 GenericArgumentId::NegImpl => true,
89 }
90 }
91 pub fn short_name(&self, db: &dyn SemanticGroup) -> String {
93 if let GenericArgumentId::Type(ty) = self { ty.short_name(db) } else { self.format(db) }
94 }
95}
96impl DebugWithDb<dyn SemanticGroup> for GenericArgumentId {
97 fn fmt(
98 &self,
99 f: &mut std::fmt::Formatter<'_>,
100 db: &(dyn SemanticGroup + 'static),
101 ) -> std::fmt::Result {
102 match self {
103 GenericArgumentId::Type(id) => write!(f, "{:?}", id.debug(db)),
104 GenericArgumentId::Constant(id) => write!(f, "{:?}", id.debug(db)),
105 GenericArgumentId::Impl(id) => write!(f, "{:?}", id.debug(db)),
106 GenericArgumentId::NegImpl => write!(f, "_"),
107 }
108 }
109}
110
111#[derive(Clone, Debug, Hash, PartialEq, Eq)]
117pub enum GenericArgumentHead {
118 Type(TypeHead),
119 Impl(ImplHead),
120 Const,
121 NegImpl,
122}
123
124#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
126pub enum GenericParam {
127 Type(GenericParamType),
128 Const(GenericParamConst),
130 Impl(GenericParamImpl),
131 NegImpl(GenericParamImpl),
132}
133impl GenericParam {
134 pub fn id(&self) -> GenericParamId {
135 match self {
136 GenericParam::Type(param) => param.id,
137 GenericParam::Const(param) => param.id,
138 GenericParam::Impl(param) => param.id,
139 GenericParam::NegImpl(param) => param.id,
140 }
141 }
142 pub fn kind(&self) -> GenericKind {
143 match self {
144 GenericParam::Type(_) => GenericKind::Type,
145 GenericParam::Const(_) => GenericKind::Const,
146 GenericParam::Impl(_) => GenericKind::Impl,
147 GenericParam::NegImpl(_) => GenericKind::NegImpl,
148 }
149 }
150 pub fn stable_ptr(&self, db: &dyn DefsGroup) -> ast::GenericParamPtr {
151 self.id().stable_ptr(db)
152 }
153 pub fn as_arg(&self, db: &dyn SemanticGroup) -> GenericArgumentId {
155 match self {
156 GenericParam::Type(param_type) => {
157 GenericArgumentId::Type(TypeLongId::GenericParameter(param_type.id).intern(db))
158 }
159 GenericParam::Const(param_const) => {
160 GenericArgumentId::Constant(ConstValue::Generic(param_const.id).intern(db))
161 }
162 GenericParam::Impl(param_impl) => {
163 GenericArgumentId::Impl(ImplLongId::GenericParameter(param_impl.id).intern(db))
164 }
165 GenericParam::NegImpl(_) => GenericArgumentId::NegImpl,
166 }
167 }
168}
169impl DebugWithDb<dyn SemanticGroup> for GenericParam {
170 fn fmt(
171 &self,
172 f: &mut std::fmt::Formatter<'_>,
173 db: &(dyn SemanticGroup + 'static),
174 ) -> std::fmt::Result {
175 write!(f, "{:?}", self.id().debug(db))
176 }
177}
178
179pub fn generic_params_to_args(
181 params: &[GenericParam],
182 db: &dyn SemanticGroup,
183) -> Vec<GenericArgumentId> {
184 params.iter().map(|param| param.as_arg(db)).collect()
185}
186
187#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
188#[debug_db(dyn SemanticGroup + 'static)]
189pub struct GenericParamType {
190 pub id: GenericParamId,
191}
192#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
193#[debug_db(dyn SemanticGroup + 'static)]
194pub struct GenericParamConst {
195 pub id: GenericParamId,
196 pub ty: TypeId,
197}
198#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, SemanticObject)]
199#[debug_db(dyn SemanticGroup + 'static)]
200pub struct GenericParamImpl {
201 pub id: GenericParamId,
202 pub concrete_trait: Maybe<ConcreteTraitId>,
203 pub type_constraints: OrderedHashMap<ConcreteTraitTypeId, TypeId>,
204}
205impl Hash for GenericParamImpl {
206 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
207 self.id.hash(state);
208 self.concrete_trait.hash(state);
209 self.type_constraints.iter().for_each(|(trait_type_id, type_id)| {
210 trait_type_id.hash(state);
211 type_id.hash(state);
212 });
213 }
214}
215
216#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
218#[debug_db(dyn SemanticGroup + 'static)]
219pub struct GenericParamData {
220 pub generic_param: Maybe<GenericParam>,
221 pub diagnostics: Diagnostics<SemanticDiagnostic>,
222 pub resolver_data: Arc<ResolverData>,
223}
224
225#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
227#[debug_db(dyn SemanticGroup + 'static)]
228pub struct GenericParamsData {
229 pub generic_params: Vec<GenericParam>,
230 pub diagnostics: Diagnostics<SemanticDiagnostic>,
231 pub resolver_data: Arc<ResolverData>,
232}
233
234pub fn generic_param_semantic(
238 db: &dyn SemanticGroup,
239 generic_param_id: GenericParamId,
240) -> Maybe<GenericParam> {
241 db.priv_generic_param_data(generic_param_id, false)?.generic_param
242}
243
244pub fn generic_param_diagnostics(
246 db: &dyn SemanticGroup,
247 generic_param_id: GenericParamId,
248) -> Diagnostics<SemanticDiagnostic> {
249 db.priv_generic_param_data(generic_param_id, false)
250 .map(|data| data.diagnostics)
251 .unwrap_or_default()
252}
253
254pub fn generic_param_resolver_data(
256 db: &dyn SemanticGroup,
257 generic_param_id: GenericParamId,
258) -> Maybe<Arc<ResolverData>> {
259 Ok(db.priv_generic_param_data(generic_param_id, false)?.resolver_data)
260}
261
262pub fn generic_impl_param_trait(
264 db: &dyn SemanticGroup,
265 generic_param_id: GenericParamId,
266) -> Maybe<TraitId> {
267 let syntax_db = db.upcast();
268 let module_file_id = generic_param_id.module_file_id(db.upcast());
269 let option_generic_params_syntax = generic_param_generic_params_list(db, generic_param_id)?;
270 let generic_params_syntax = extract_matches!(
271 option_generic_params_syntax,
272 ast::OptionWrappedGenericParamList::WrappedGenericParamList
273 );
274 let generic_param_syntax = generic_params_syntax
275 .generic_params(syntax_db)
276 .elements(syntax_db)
277 .into_iter()
278 .find(|param_syntax| {
279 GenericParamLongId(module_file_id, param_syntax.stable_ptr()).intern(db)
280 == generic_param_id
281 })
282 .unwrap();
283
284 let trait_path_syntax = match generic_param_syntax {
285 ast::GenericParam::ImplNamed(syntax) => syntax.trait_path(syntax_db),
286 ast::GenericParam::ImplAnonymous(syntax) => syntax.trait_path(syntax_db),
287 _ => {
288 panic!("generic_impl_param_trait() called on a non impl generic param.")
289 }
290 };
291
292 let mut diagnostics = SemanticDiagnostics::default();
293 let inference_id = InferenceId::GenericImplParamTrait(generic_param_id);
294 let mut resolver = Resolver::new(db, module_file_id, inference_id);
298
299 resolve_trait_path(&mut diagnostics, &mut resolver, &trait_path_syntax)
300}
301
302pub fn priv_generic_param_data(
306 db: &dyn SemanticGroup,
307 generic_param_id: GenericParamId,
308 in_cycle: bool,
309) -> Maybe<GenericParamData> {
310 if in_cycle {
311 let mut diagnostics = SemanticDiagnostics::default();
312 return Ok(GenericParamData {
313 generic_param: Err(diagnostics.report(
314 generic_param_id.stable_ptr(db.upcast()).untyped(),
315 SemanticDiagnosticKind::ImplRequirementCycle,
316 )),
317 diagnostics: diagnostics.build(),
318 resolver_data: Arc::new(ResolverData::new(
319 generic_param_id.module_file_id(db.upcast()),
320 InferenceId::GenericParam(generic_param_id),
321 )),
322 });
323 }
324 let syntax_db: &dyn SyntaxGroup = db.upcast();
325 let module_file_id = generic_param_id.module_file_id(db.upcast());
326 let mut diagnostics = SemanticDiagnostics::default();
327 let parent_item_id = generic_param_id.generic_item(db.upcast());
328 let lookup_item: LookupItemId = parent_item_id.into();
329 let context_resolver_data = lookup_item.resolver_context(db)?;
330 let inference_id = InferenceId::GenericParam(generic_param_id);
331 let mut resolver =
332 Resolver::with_data(db, (*context_resolver_data).clone_with_inference_id(db, inference_id));
333 resolver.set_feature_config(
334 &lookup_item,
335 &lookup_item.untyped_stable_ptr(db.upcast()).lookup(db.upcast()),
336 &mut diagnostics,
337 );
338 let generic_params_syntax = extract_matches!(
339 generic_param_generic_params_list(db, generic_param_id)?,
340 ast::OptionWrappedGenericParamList::WrappedGenericParamList
341 );
342
343 let mut opt_generic_param_syntax = None;
344 for param_syntax in
345 generic_params_syntax.generic_params(syntax_db).elements(syntax_db).into_iter()
346 {
347 let cur_generic_param_id =
348 GenericParamLongId(module_file_id, param_syntax.stable_ptr()).intern(db);
349 resolver.add_generic_param(cur_generic_param_id);
350
351 if cur_generic_param_id == generic_param_id {
352 opt_generic_param_syntax = Some(param_syntax);
353 }
354 }
355 let generic_param_syntax =
356 opt_generic_param_syntax.expect("Query called on a non existing generic param.");
357 let param_semantic = semantic_from_generic_param_ast(
358 db,
359 &mut resolver,
360 &mut diagnostics,
361 module_file_id,
362 &generic_param_syntax,
363 parent_item_id,
364 );
365 let inference = &mut resolver.inference();
366 inference.finalize(&mut diagnostics, generic_param_syntax.stable_ptr().untyped());
367
368 let param_semantic = inference.rewrite(param_semantic).no_err();
369 let resolver_data = Arc::new(resolver.data);
370 Ok(GenericParamData {
371 generic_param: Ok(param_semantic),
372 diagnostics: diagnostics.build(),
373 resolver_data,
374 })
375}
376
377pub fn priv_generic_param_data_cycle(
379 db: &dyn SemanticGroup,
380 _cycle: &salsa::Cycle,
381 generic_param_id: &GenericParamId,
382 _in_cycle: &bool,
383) -> Maybe<GenericParamData> {
384 priv_generic_param_data(db, *generic_param_id, true)
385}
386
387pub fn generic_params_type_constraints(
389 db: &dyn SemanticGroup,
390 generic_params: Vec<GenericParamId>,
391) -> Vec<(TypeId, TypeId)> {
392 let mut constraints = vec![];
393 for param in &generic_params {
394 let GenericParam::Impl(imp) = db.generic_param_semantic(*param).unwrap() else {
395 continue;
396 };
397 let Ok(concrete_trait_id) = imp.concrete_trait else {
398 continue;
399 };
400 for (concrete_trait_type_id, ty1) in imp.type_constraints {
401 let trait_ty = concrete_trait_type_id.trait_type(db);
402 let impl_type = TypeLongId::ImplType(ImplTypeId::new(
403 ImplLongId::GenericParameter(*param).intern(db),
404 trait_ty,
405 db,
406 ))
407 .intern(db);
408 constraints.push((impl_type, ty1));
409 }
410 let ConcreteTraitLongId { trait_id, generic_args } = concrete_trait_id.lookup_intern(db);
411 if trait_id != get_core_trait(db, CoreTraitContext::MetaProgramming, "TypeEqual".into()) {
412 continue;
413 }
414 let [GenericArgumentId::Type(ty0), GenericArgumentId::Type(ty1)] = generic_args.as_slice()
415 else {
416 unreachable!("TypeEqual should have 2 arguments");
417 };
418 constraints.push((*ty0, *ty1));
419 }
420 constraints
421}
422
423fn generic_param_generic_params_list(
427 db: &dyn SemanticGroup,
428 generic_param_id: GenericParamId,
429) -> Maybe<ast::OptionWrappedGenericParamList> {
430 let generic_param_long_id = generic_param_id.lookup_intern(db);
431
432 let syntax_db = db.upcast();
434 let wrapped_generic_param_list = generic_param_long_id.1.0.nth_parent(syntax_db, 2);
435
436 Ok(ast::OptionWrappedGenericParamListPtr(wrapped_generic_param_list).lookup(syntax_db))
437}
438
439pub fn semantic_generic_params(
442 db: &dyn SemanticGroup,
443 diagnostics: &mut SemanticDiagnostics,
444 resolver: &mut Resolver<'_>,
445 module_file_id: ModuleFileId,
446 generic_params: &ast::OptionWrappedGenericParamList,
447) -> Vec<GenericParam> {
448 semantic_generic_params_ex(db, diagnostics, resolver, module_file_id, generic_params, false)
449}
450
451pub fn semantic_generic_params_ex(
452 db: &dyn SemanticGroup,
453 diagnostics: &mut SemanticDiagnostics,
454 resolver: &mut Resolver<'_>,
455 module_file_id: ModuleFileId,
456 generic_params: &ast::OptionWrappedGenericParamList,
457 in_cycle: bool,
458) -> Vec<GenericParam> {
459 let syntax_db = db.upcast();
460 match generic_params {
461 syntax::node::ast::OptionWrappedGenericParamList::Empty(_) => vec![],
462 syntax::node::ast::OptionWrappedGenericParamList::WrappedGenericParamList(syntax) => syntax
463 .generic_params(syntax_db)
464 .elements(syntax_db)
465 .iter()
466 .filter_map(|param_syntax| {
467 let generic_param_id =
468 GenericParamLongId(module_file_id, param_syntax.stable_ptr()).intern(db);
469 let generic_param_data =
470 db.priv_generic_param_data(generic_param_id, in_cycle).ok()?;
471 let generic_param = generic_param_data.generic_param;
472 diagnostics.extend(generic_param_data.diagnostics);
473 resolver.add_generic_param(generic_param_id);
474 resolver
475 .data
476 .used_items
477 .extend(generic_param_data.resolver_data.used_items.iter().copied());
478 generic_param.ok()
479 })
480 .collect(),
481 }
482}
483
484fn are_negative_impls_enabled(db: &dyn SemanticGroup, module_file_id: ModuleFileId) -> bool {
486 let owning_crate = module_file_id.0.owning_crate(db.upcast());
487 let Some(config) = db.crate_config(owning_crate) else { return false };
488 config.settings.experimental_features.negative_impls
489}
490
491fn is_associated_item_constraints_enabled(
493 db: &dyn SemanticGroup,
494 module_file_id: ModuleFileId,
495) -> bool {
496 let owning_crate = module_file_id.0.owning_crate(db.upcast());
497 db.crate_config(owning_crate)
498 .is_some_and(|c| c.settings.experimental_features.associated_item_constraints)
499}
500
501fn semantic_from_generic_param_ast(
503 db: &dyn SemanticGroup,
504 resolver: &mut Resolver<'_>,
505 diagnostics: &mut SemanticDiagnostics,
506 module_file_id: ModuleFileId,
507 param_syntax: &ast::GenericParam,
508 parent_item_id: GenericItemId,
509) -> GenericParam {
510 let id = GenericParamLongId(module_file_id, param_syntax.stable_ptr()).intern(db);
511 let mut item_constraints_into_option = |constraint| match constraint {
512 OptionAssociatedItemConstraints::Empty(_) => None,
513 OptionAssociatedItemConstraints::AssociatedItemConstraints(associated_type_args) => {
514 if !is_associated_item_constraints_enabled(db, module_file_id) {
515 diagnostics.report(
516 associated_type_args.stable_ptr(),
517 SemanticDiagnosticKind::TypeConstraintsSyntaxNotEnabled,
518 );
519 }
520 Some(associated_type_args)
521 }
522 };
523 match param_syntax {
524 ast::GenericParam::Type(_) => GenericParam::Type(GenericParamType { id }),
525 ast::GenericParam::Const(syntax) => {
526 let ty = resolve_type(db, diagnostics, resolver, &syntax.ty(db.upcast()));
527 GenericParam::Const(GenericParamConst { id, ty })
528 }
529 ast::GenericParam::ImplNamed(syntax) => {
530 let path_syntax = syntax.trait_path(db.upcast());
531 let item_constrains = item_constraints_into_option(syntax.type_constrains(db.upcast()));
532 GenericParam::Impl(impl_generic_param_semantic(
533 db,
534 resolver,
535 diagnostics,
536 &path_syntax,
537 item_constrains,
538 id,
539 ))
540 }
541 ast::GenericParam::ImplAnonymous(syntax) => {
542 let path_syntax = syntax.trait_path(db.upcast());
543 let item_constrains = item_constraints_into_option(syntax.type_constrains(db.upcast()));
544 GenericParam::Impl(impl_generic_param_semantic(
545 db,
546 resolver,
547 diagnostics,
548 &path_syntax,
549 item_constrains,
550 id,
551 ))
552 }
553 ast::GenericParam::NegativeImpl(syntax) => {
554 if !are_negative_impls_enabled(db, module_file_id) {
555 diagnostics.report(param_syntax, SemanticDiagnosticKind::NegativeImplsNotEnabled);
556 }
557
558 if !matches!(parent_item_id, GenericItemId::ModuleItem(GenericModuleItemId::Impl(_))) {
559 diagnostics.report(param_syntax, SemanticDiagnosticKind::NegativeImplsOnlyOnImpls);
560 }
561
562 let path_syntax = syntax.trait_path(db.upcast());
563 GenericParam::NegImpl(impl_generic_param_semantic(
564 db,
565 resolver,
566 diagnostics,
567 &path_syntax,
568 None,
569 id,
570 ))
571 }
572 }
573}
574
575fn impl_generic_param_semantic(
577 db: &dyn SemanticGroup,
578 resolver: &mut Resolver<'_>,
579 diagnostics: &mut SemanticDiagnostics,
580 path_syntax: &ast::ExprPath,
581 item_constraints: Option<AssociatedItemConstraints>,
582 id: GenericParamId,
583) -> GenericParamImpl {
584 let concrete_trait = resolver
585 .resolve_concrete_path(diagnostics, path_syntax, NotFoundItemType::Trait)
586 .and_then(|resolved_item| {
587 try_extract_matches!(resolved_item, ResolvedConcreteItem::Trait).ok_or_else(|| {
588 diagnostics.report(path_syntax, SemanticDiagnosticKind::UnknownTrait)
589 })
590 });
591 let type_constraints = concrete_trait
592 .ok()
593 .and_then(|concrete_trait| {
594 item_constraints.map(|type_constraints| (concrete_trait, type_constraints))
595 })
596 .map(|(concrete_trait_id, constraints)| {
597 let mut map = OrderedHashMap::default();
598
599 for constraint in
600 constraints.associated_item_constraints(db.upcast()).elements(db.upcast())
601 {
602 let Some(trait_type_id) = db
603 .trait_type_by_name(
604 concrete_trait_id.trait_id(db),
605 constraint.item(db.upcast()).text(db.upcast()),
606 )
607 .unwrap()
608 else {
609 diagnostics.report(
610 constraint.stable_ptr(),
611 SemanticDiagnosticKind::NonTraitTypeConstrained {
612 identifier: constraint.item(db.upcast()).text(db.upcast()),
613 concrete_trait_id,
614 },
615 );
616 return map;
617 };
618
619 let concrete_trait_type_id =
620 ConcreteTraitTypeId::new(db, concrete_trait_id, trait_type_id);
621 match map.entry(concrete_trait_type_id) {
622 Entry::Vacant(entry) => {
623 entry.insert(resolve_type(
624 db,
625 diagnostics,
626 resolver,
627 &constraint.value(db.upcast()),
628 ));
629 }
630 Entry::Occupied(_) => {
631 diagnostics.report(
632 path_syntax,
633 SemanticDiagnosticKind::DuplicateTypeConstraint {
634 concrete_trait_type_id,
635 },
636 );
637 }
638 }
639 }
640 map
641 })
642 .unwrap_or_default();
643
644 GenericParamImpl { id, concrete_trait, type_constraints }
645}