cairo_lang_semantic/items/
generics.rs

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/// Generic argument.
38/// A value assigned to a generic parameter.
39/// May be a type, impl, constant, etc..
40#[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    /// Returns the [GenericArgumentHead] for a generic argument if available.
65    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    /// Returns true if the generic argument does not depend on any generics.
74    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    /// Returns true if the generic argument does not depend on impl or type variables.
83    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    /// Short name of the generic argument.
92    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/// Head of a generic argument.
112///
113/// A non-param non-variable generic argument has a head, which represents the kind of the root node
114/// in its tree. This is used for caching queries for fast lookups when the generic argument is not
115/// completely inferred yet.
116#[derive(Clone, Debug, Hash, PartialEq, Eq)]
117pub enum GenericArgumentHead {
118    Type(TypeHead),
119    Impl(ImplHead),
120    Const,
121    NegImpl,
122}
123
124/// Generic parameter.
125#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
126pub enum GenericParam {
127    Type(GenericParamType),
128    // TODO(spapini): Add expression.
129    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    /// Returns the generic param as a generic argument.
154    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
179/// Converts each generic param to a generic argument that passes the same generic param.
180pub 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/// The result of the computation of the semantic model of a generic parameter.
217#[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/// The result of the computation of the semantic model of a generic parameters list.
226#[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
234// --- Selectors ---
235
236/// Query implementation of [crate::db::SemanticGroup::generic_param_semantic].
237pub 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
244/// Query implementation of [crate::db::SemanticGroup::generic_param_diagnostics].
245pub 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
254/// Query implementation of [crate::db::SemanticGroup::generic_param_resolver_data].
255pub 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
262/// Query implementation of [crate::db::SemanticGroup::generic_impl_param_trait].
263pub 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    // TODO(spapini): We should not create a new resolver -  we are missing the other generic params
295    // in the context.
296    // Remove also GenericImplParamTrait.
297    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
302// --- Computation ---
303
304/// Query implementation of [crate::db::SemanticGroup::priv_generic_param_data].
305pub 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
377/// Cycle handling for [crate::db::SemanticGroup::priv_generic_param_data].
378pub 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
387/// Query implementation of [crate::db::SemanticGroup::generic_params_type_constraints].
388pub 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
423// --- Helpers ---
424
425/// Returns the generic parameters list AST node of a generic parameter.
426fn 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    // The generic params list is 2 level up the tree.
433    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
439/// Returns the semantic model of a generic parameters list given the list AST, and updates the
440/// diagnostics and resolver accordingly.
441pub 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
484/// Returns true if negative impls are enabled in the module.
485fn 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
491/// Returns true if associated_item_constraints is enabled in the module.
492fn 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
501/// Computes the semantic model of a generic parameter give its ast.
502fn 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
575/// Computes the semantic model of an impl generic parameter given its trait path.
576fn 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}