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