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