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 }
405}
406
407#[salsa::tracked(cycle_result=generic_param_data_cycle, returns(ref))]
409fn generic_param_data<'db>(
410 db: &'db dyn Database,
411 generic_param_id: GenericParamId<'db>,
412 in_cycle: bool,
413) -> Maybe<GenericParamData<'db>> {
414 let module_id = generic_param_id.parent_module(db);
415 if in_cycle {
416 let mut diagnostics = SemanticDiagnostics::new(module_id);
417 return Ok(GenericParamData {
418 generic_param: Err(diagnostics.report(
419 generic_param_id.stable_ptr(db).untyped(),
420 SemanticDiagnosticKind::ImplRequirementCycle,
421 )),
422 diagnostics: diagnostics.build(),
423 resolver_data: Arc::new(ResolverData::new(
424 generic_param_id.parent_module(db),
425 InferenceId::GenericParam(generic_param_id),
426 )),
427 });
428 }
429 let mut diagnostics = SemanticDiagnostics::new(module_id);
430 let parent_item_id = generic_param_id.generic_item(db);
431 let lookup_item: LookupItemId<'_> = parent_item_id.into();
432 let context_resolver_data = lookup_item.resolver_context(db)?;
433 let inference_id = InferenceId::GenericParam(generic_param_id);
434 let mut resolver =
435 Resolver::with_data(db, (*context_resolver_data).clone_with_inference_id(db, inference_id));
436 resolver.set_feature_config(
437 &lookup_item,
438 &lookup_item.untyped_stable_ptr(db).lookup(db),
439 &mut diagnostics,
440 );
441 let generic_params_syntax = extract_matches!(
442 generic_param_generic_params_list(db, generic_param_id)?,
443 ast::OptionWrappedGenericParamList::WrappedGenericParamList
444 );
445
446 let mut opt_generic_param_syntax = None;
447 for param_syntax in generic_params_syntax.generic_params(db).elements(db) {
448 let cur_generic_param_id =
449 GenericParamLongId(module_id, param_syntax.stable_ptr(db)).intern(db);
450 resolver.add_generic_param(cur_generic_param_id);
451
452 if cur_generic_param_id == generic_param_id {
453 opt_generic_param_syntax = Some(param_syntax);
454 }
455 }
456 let generic_param_syntax =
457 opt_generic_param_syntax.expect("Query called on a non existing generic param.");
458 let param_semantic = semantic_from_generic_param_ast(
459 db,
460 &mut resolver,
461 &mut diagnostics,
462 module_id,
463 &generic_param_syntax,
464 parent_item_id,
465 )?;
466 let inference = &mut resolver.inference();
467 inference.finalize(&mut diagnostics, generic_param_syntax.stable_ptr(db).untyped());
468
469 let param_semantic = inference.rewrite(param_semantic).no_err();
470 let resolver_data = Arc::new(resolver.data);
471 Ok(GenericParamData {
472 generic_param: Ok(param_semantic),
473 diagnostics: diagnostics.build(),
474 resolver_data,
475 })
476}
477
478fn generic_param_data_cycle<'db>(
480 db: &'db dyn Database,
481 _id: salsa::Id,
482 generic_param_id: GenericParamId<'db>,
483 _in_cycle: bool,
484) -> Maybe<GenericParamData<'db>> {
485 generic_param_data(db, generic_param_id, true).clone()
486}
487
488#[salsa::tracked(returns(ref))]
490fn generic_params_type_constraints<'db>(
491 db: &'db dyn Database,
492 _tracked: Tracked,
493 generic_params: Vec<GenericParamId<'db>>,
494) -> Vec<(TypeId<'db>, TypeId<'db>)> {
495 let mut constraints = vec![];
496 for param in &generic_params {
497 let Ok(GenericParam::Impl(imp)) = db.generic_param_semantic(*param) else {
498 continue;
499 };
500 let Ok(concrete_trait_id) = imp.concrete_trait else {
501 continue;
502 };
503 for (trait_ty, ty1) in imp.type_constraints {
504 let impl_type = TypeLongId::ImplType(ImplTypeId::new(
505 ImplLongId::GenericParameter(*param).intern(db),
506 trait_ty,
507 db,
508 ))
509 .intern(db);
510 constraints.push((impl_type, ty1));
511 }
512 let ConcreteTraitLongId { trait_id, generic_args } = concrete_trait_id.long(db);
513 if trait_id != &db.core_info().type_eq_trt {
514 continue;
515 }
516 let [GenericArgumentId::Type(ty0), GenericArgumentId::Type(ty1)] = generic_args.as_slice()
517 else {
518 unreachable!("TypeEqual should have 2 arguments");
519 };
520 constraints.push((*ty0, *ty1));
521 }
522 constraints
523}
524
525fn generic_param_generic_params_list<'db>(
529 db: &'db dyn Database,
530 generic_param_id: GenericParamId<'db>,
531) -> Maybe<ast::OptionWrappedGenericParamList<'db>> {
532 let generic_param_long_id = generic_param_id.long(db);
533
534 let wrapped_generic_param_list = generic_param_long_id.1.0.nth_parent(db, 2);
536
537 Ok(ast::OptionWrappedGenericParamListPtr(wrapped_generic_param_list).lookup(db))
538}
539
540pub fn semantic_generic_params<'db>(
543 db: &'db dyn Database,
544 diagnostics: &mut SemanticDiagnostics<'db>,
545 resolver: &mut Resolver<'db>,
546 module_id: ModuleId<'db>,
547 generic_params: &ast::OptionWrappedGenericParamList<'db>,
548) -> Vec<GenericParam<'db>> {
549 semantic_generic_params_ex(db, diagnostics, resolver, module_id, generic_params, false)
550}
551
552pub fn semantic_generic_params_ex<'db>(
553 db: &'db dyn Database,
554 diagnostics: &mut SemanticDiagnostics<'db>,
555 resolver: &mut Resolver<'db>,
556 module_id: ModuleId<'db>,
557 generic_params: &ast::OptionWrappedGenericParamList<'db>,
558 in_cycle: bool,
559) -> Vec<GenericParam<'db>> {
560 match generic_params {
561 syntax::node::ast::OptionWrappedGenericParamList::Empty(_) => vec![],
562 syntax::node::ast::OptionWrappedGenericParamList::WrappedGenericParamList(syntax) => syntax
563 .generic_params(db)
564 .elements(db)
565 .filter_map(|param_syntax| {
566 let generic_param_id =
567 GenericParamLongId(module_id, param_syntax.stable_ptr(db)).intern(db);
568 let data = generic_param_data(db, generic_param_id, in_cycle).as_ref().ok()?;
569 let generic_param = data.generic_param.clone();
570 diagnostics.extend(data.diagnostics.clone());
571 resolver.add_generic_param(generic_param_id);
572 resolver.data.used_uses.extend(data.resolver_data.used_uses.iter().copied());
573 generic_param.ok()
574 })
575 .collect(),
576 }
577}
578
579fn are_negative_impls_enabled<'db>(db: &dyn Database, module_id: ModuleId<'db>) -> bool {
581 let owning_crate = module_id.owning_crate(db);
582 let Some(config) = db.crate_config(owning_crate) else { return false };
583 config.settings.experimental_features.negative_impls
584}
585
586fn is_associated_item_constraints_enabled(db: &dyn Database, module_id: ModuleId<'_>) -> bool {
588 let owning_crate = module_id.owning_crate(db);
589 db.crate_config(owning_crate)
590 .is_some_and(|c| c.settings.experimental_features.associated_item_constraints)
591}
592
593fn semantic_from_generic_param_ast<'db>(
595 db: &'db dyn Database,
596 resolver: &mut Resolver<'db>,
597 diagnostics: &mut SemanticDiagnostics<'db>,
598 module_id: ModuleId<'db>,
599 param_syntax: &ast::GenericParam<'db>,
600 parent_item_id: GenericItemId<'db>,
601) -> Maybe<GenericParam<'db>> {
602 let id = GenericParamLongId(module_id, param_syntax.stable_ptr(db)).intern(db);
603 let mut item_constraints_into_option = |constraint| match constraint {
604 OptionAssociatedItemConstraints::Empty(_) => None,
605 OptionAssociatedItemConstraints::AssociatedItemConstraints(associated_type_args) => {
606 if !is_associated_item_constraints_enabled(db, module_id) {
607 diagnostics.report(
608 associated_type_args.stable_ptr(db),
609 SemanticDiagnosticKind::TypeConstraintsSyntaxNotEnabled,
610 );
611 }
612 Some(associated_type_args)
613 }
614 };
615 Ok(match param_syntax {
616 ast::GenericParam::Type(_) => GenericParam::Type(GenericParamType { id }),
617 ast::GenericParam::Const(syntax) => {
618 let ty = resolve_type(db, diagnostics, resolver, &syntax.ty(db));
619 GenericParam::Const(GenericParamConst { id, ty })
620 }
621 ast::GenericParam::ImplNamed(syntax) => {
622 let path_syntax = syntax.trait_path(db);
623 let item_constrains = item_constraints_into_option(syntax.type_constrains(db));
624 GenericParam::Impl(impl_generic_param_semantic(
625 db,
626 resolver,
627 diagnostics,
628 &path_syntax,
629 item_constrains,
630 id,
631 ))
632 }
633 ast::GenericParam::ImplAnonymous(syntax) => {
634 let path_syntax = syntax.trait_path(db);
635 let item_constrains = item_constraints_into_option(syntax.type_constrains(db));
636 GenericParam::Impl(impl_generic_param_semantic(
637 db,
638 resolver,
639 diagnostics,
640 &path_syntax,
641 item_constrains,
642 id,
643 ))
644 }
645 ast::GenericParam::NegativeImpl(syntax) => {
646 if !are_negative_impls_enabled(db, module_id) {
647 diagnostics.report(
648 param_syntax.stable_ptr(db),
649 SemanticDiagnosticKind::NegativeImplsNotEnabled,
650 );
651 }
652
653 if !matches!(parent_item_id, GenericItemId::ModuleItem(GenericModuleItemId::Impl(_))) {
654 diagnostics.report(
655 param_syntax.stable_ptr(db),
656 SemanticDiagnosticKind::NegativeImplsOnlyOnImpls,
657 );
658 }
659
660 let path_syntax = syntax.trait_path(db);
661
662 let neg_impl =
663 impl_generic_param_semantic(db, resolver, diagnostics, &path_syntax, None, id);
664 for param in db.trait_generic_params(neg_impl.concrete_trait?.trait_id(db))? {
665 if matches!(param, GenericParam::Type(_) | GenericParam::Const(_)) {
666 continue;
667 }
668 diagnostics.report(
669 param.stable_ptr(db),
670 SemanticDiagnosticKind::OnlyTypeOrConstParamsInNegImpl,
671 );
672 }
673
674 GenericParam::NegImpl(neg_impl)
675 }
676 })
677}
678
679fn impl_generic_param_semantic<'db>(
681 db: &'db dyn Database,
682 resolver: &mut Resolver<'db>,
683 diagnostics: &mut SemanticDiagnostics<'db>,
684 path_syntax: &ast::ExprPath<'db>,
685 item_constraints: Option<AssociatedItemConstraints<'db>>,
686 id: GenericParamId<'db>,
687) -> GenericParamImpl<'db> {
688 let concrete_trait = resolver
689 .resolve_concrete_path(diagnostics, path_syntax, NotFoundItemType::Trait)
690 .and_then(|resolved_item| match resolved_item {
691 ResolvedConcreteItem::Trait(id) | ResolvedConcreteItem::SelfTrait(id) => Ok(id),
692 _ => Err(diagnostics
693 .report(path_syntax.stable_ptr(db), SemanticDiagnosticKind::UnknownTrait)),
694 });
695 let type_constraints = concrete_trait
696 .ok()
697 .zip(item_constraints)
698 .map(|(concrete_trait_id, constraints)| {
699 let mut map = OrderedHashMap::default();
700
701 for constraint in constraints.associated_item_constraints(db).elements(db) {
702 let Ok(trait_type_id_opt) = db.trait_type_by_name(
703 concrete_trait_id.trait_id(db),
704 constraint.item(db).text(db),
705 ) else {
706 continue;
707 };
708 let Some(trait_type_id) = trait_type_id_opt else {
709 diagnostics.report(
710 constraint.stable_ptr(db),
711 SemanticDiagnosticKind::NonTraitTypeConstrained {
712 identifier: constraint.item(db).text(db),
713 concrete_trait_id,
714 },
715 );
716 continue;
717 };
718
719 let concrete_trait_type_id =
720 ConcreteTraitTypeId::new_from_data(db, concrete_trait_id, trait_type_id);
721 match map.entry(trait_type_id) {
722 Entry::Vacant(entry) => {
723 entry.insert(resolve_type(
724 db,
725 diagnostics,
726 resolver,
727 &constraint.value(db),
728 ));
729 }
730 Entry::Occupied(_) => {
731 diagnostics.report(
732 path_syntax.stable_ptr(db),
733 SemanticDiagnosticKind::DuplicateTypeConstraint {
734 concrete_trait_type_id,
735 },
736 );
737 }
738 }
739 }
740 map
741 })
742 .unwrap_or_default();
743
744 GenericParamImpl { id, concrete_trait, type_constraints }
745}
746
747struct CountingWriter<'a, 'b> {
749 inner: &'a mut std::fmt::Formatter<'b>,
750 count: usize,
751}
752
753impl<'a, 'b> CountingWriter<'a, 'b> {
754 pub fn new(inner: &'a mut std::fmt::Formatter<'b>) -> Self {
755 Self { inner, count: 0 }
756 }
757
758 pub fn count(&self) -> usize {
759 self.count
760 }
761}
762
763impl<'a, 'b> std::fmt::Write for CountingWriter<'a, 'b> {
764 fn write_str(&mut self, s: &str) -> std::fmt::Result {
765 self.count += s.len();
766 self.inner.write_str(s)
767 }
768}
769
770pub fn displayable_concrete<'db, 'a: 'db, Name: Display>(
773 db: &'db dyn Database,
774 name: &'a Name,
775 generic_args: &'a [GenericArgumentId<'db>],
776) -> impl Display + 'a + 'db {
777 DisplayableConcrete { db, name, generic_args }
778}
779
780struct DisplayableConcrete<'a, 'db, Name> {
782 db: &'db dyn Database,
783 name: &'a Name,
784 generic_args: &'a [GenericArgumentId<'db>],
785}
786impl<Name: Display> Display for DisplayableConcrete<'_, '_, Name> {
787 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
788 let mut f = CountingWriter::new(f);
789 write!(f, "{}", self.name)?;
790 let mut generic_args = self.generic_args.iter();
791 if let Some(first) = generic_args.next() {
792 const CHARS_BOUND: usize = 500;
794 write!(f, "::<")?;
795 write!(f, "{}", first.format(self.db))?;
796
797 for arg in generic_args {
798 write!(f, ", ")?;
799 if f.count() > CHARS_BOUND {
800 write!(f, "{}", arg.short_name(self.db))?;
802 } else {
803 write!(f, "{}", arg.format(self.db))?;
804 }
805 }
806 write!(f, ">")?;
807 }
808 Ok(())
809 }
810}
811
812pub trait GenericParamSemantic<'db>: Database {
814 fn generic_param_semantic(
816 &'db self,
817 generic_param: GenericParamId<'db>,
818 ) -> Maybe<GenericParam<'db>> {
819 generic_param_data(self.as_dyn_database(), generic_param, false)
820 .maybe_as_ref()?
821 .generic_param
822 .clone()
823 }
824 fn generic_param_diagnostics(
826 &'db self,
827 generic_param: GenericParamId<'db>,
828 ) -> Diagnostics<'db, SemanticDiagnostic<'db>> {
829 generic_param_data(self.as_dyn_database(), generic_param, false)
830 .as_ref()
831 .map(|data| data.diagnostics.clone())
832 .unwrap_or_default()
833 }
834 fn generic_param_resolver_data(
836 &'db self,
837 generic_param: GenericParamId<'db>,
838 ) -> Maybe<Arc<ResolverData<'db>>> {
839 Ok(generic_param_data(self.as_dyn_database(), generic_param, false)
840 .maybe_as_ref()?
841 .resolver_data
842 .clone())
843 }
844 fn generic_impl_param_trait(
847 &'db self,
848 generic_param_id: GenericParamId<'db>,
849 ) -> Maybe<TraitId<'db>> {
850 generic_impl_param_trait(self.as_dyn_database(), generic_param_id)
851 }
852 fn generic_impl_param_shallow_trait_generic_args(
854 &'db self,
855 generic_param: GenericParamId<'db>,
856 ) -> Maybe<&'db [(GenericParamId<'db>, ShallowGenericArg<'db>)]> {
857 Ok(generic_impl_param_shallow_trait_generic_args(self.as_dyn_database(), generic_param)
858 .maybe_as_ref()?)
859 }
860 fn generic_params_type_constraints(
862 &'db self,
863 generic_params: Vec<GenericParamId<'db>>,
864 ) -> &'db [(TypeId<'db>, TypeId<'db>)] {
865 generic_params_type_constraints(self.as_dyn_database(), (), generic_params)
866 }
867}
868impl<'db, T: Database + ?Sized> GenericParamSemantic<'db> for T {}