cairo_lang_semantic/items/
generics.rs

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