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