1use either::Either;
4use hir_def::{
5 GenericDefId, GenericParamId, Lookup, TraitId, TypeAliasId,
6 expr_store::{
7 ExpressionStore, HygieneId,
8 path::{
9 GenericArg as HirGenericArg, GenericArgs as HirGenericArgs, GenericArgsParentheses,
10 Path, PathSegment, PathSegments,
11 },
12 },
13 hir::generics::{
14 GenericParamDataRef, TypeOrConstParamData, TypeParamData, TypeParamProvenance,
15 },
16 resolver::{ResolveValueResult, TypeNs, ValueNs},
17 signatures::TraitFlags,
18 type_ref::{TypeRef, TypeRefId},
19};
20use hir_expand::name::Name;
21use rustc_type_ir::{
22 AliasTerm, AliasTy, AliasTyKind,
23 inherent::{GenericArgs as _, Region as _, SliceLike, Ty as _},
24};
25use smallvec::SmallVec;
26use stdx::never;
27
28use crate::{
29 GenericArgsProhibitedReason, IncorrectGenericsLenKind, PathGenericsSource,
30 PathLoweringDiagnostic, TyDefId, ValueTyDefId,
31 consteval::{unknown_const, unknown_const_as_generic},
32 db::HirDatabase,
33 generics::{Generics, generics},
34 lower::{
35 LifetimeElisionKind, PathDiagnosticCallbackData, named_associated_type_shorthand_candidates,
36 },
37 next_solver::{
38 Binder, Clause, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Predicate,
39 ProjectionPredicate, Region, TraitRef, Ty,
40 },
41};
42
43use super::{
44 ImplTraitLoweringMode, TyLoweringContext, associated_type_by_name_including_super_traits,
45 const_param_ty_query, ty_query,
46};
47
48type CallbackData<'a, 'db> = Either<
49 PathDiagnosticCallbackData,
50 crate::infer::diagnostics::PathDiagnosticCallbackData<'a, 'db>,
51>;
52
53pub(crate) struct PathDiagnosticCallback<'a, 'db> {
56 pub(crate) data: CallbackData<'a, 'db>,
57 pub(crate) callback:
58 fn(&CallbackData<'_, 'db>, &mut TyLoweringContext<'db, '_>, PathLoweringDiagnostic),
59}
60
61pub(crate) struct PathLoweringContext<'a, 'b, 'db> {
62 ctx: &'a mut TyLoweringContext<'db, 'b>,
63 on_diagnostic: PathDiagnosticCallback<'a, 'db>,
64 path: &'a Path,
65 segments: PathSegments<'a>,
66 current_segment_idx: usize,
67 current_or_prev_segment: PathSegment<'a>,
69}
70
71impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
72 #[inline]
73 pub(crate) fn new(
74 ctx: &'a mut TyLoweringContext<'db, 'b>,
75 on_diagnostic: PathDiagnosticCallback<'a, 'db>,
76 path: &'a Path,
77 ) -> Self {
78 let segments = path.segments();
79 let first_segment = segments.first().unwrap_or(PathSegment::MISSING);
80 Self {
81 ctx,
82 on_diagnostic,
83 path,
84 segments,
85 current_segment_idx: 0,
86 current_or_prev_segment: first_segment,
87 }
88 }
89
90 #[inline]
91 #[cold]
92 fn on_diagnostic(&mut self, diag: PathLoweringDiagnostic) {
93 (self.on_diagnostic.callback)(&self.on_diagnostic.data, self.ctx, diag);
94 }
95
96 #[inline]
97 pub(crate) fn ty_ctx(&mut self) -> &mut TyLoweringContext<'db, 'b> {
98 self.ctx
99 }
100
101 #[inline]
102 fn current_segment_u32(&self) -> u32 {
103 self.current_segment_idx as u32
104 }
105
106 #[inline]
107 fn skip_resolved_segment(&mut self) {
108 if !matches!(self.path, Path::LangItem(..)) {
109 self.current_segment_idx += 1;
112 }
113 self.update_current_segment();
114 }
115
116 #[inline]
117 fn update_current_segment(&mut self) {
118 self.current_or_prev_segment =
119 self.segments.get(self.current_segment_idx).unwrap_or(self.current_or_prev_segment);
120 }
121
122 #[inline]
123 pub(crate) fn ignore_last_segment(&mut self) {
124 self.segments = self.segments.strip_last();
125 }
126
127 #[inline]
128 pub(crate) fn set_current_segment(&mut self, segment: usize) {
129 self.current_segment_idx = segment;
130 self.current_or_prev_segment = self
131 .segments
132 .get(segment)
133 .expect("invalid segment passed to PathLoweringContext::set_current_segment()");
134 }
135
136 #[inline]
137 fn with_lifetime_elision<T>(
138 &mut self,
139 lifetime_elision: LifetimeElisionKind<'db>,
140 f: impl FnOnce(&mut PathLoweringContext<'_, '_, 'db>) -> T,
141 ) -> T {
142 let old_lifetime_elision =
143 std::mem::replace(&mut self.ctx.lifetime_elision, lifetime_elision);
144 let result = f(self);
145 self.ctx.lifetime_elision = old_lifetime_elision;
146 result
147 }
148
149 pub(crate) fn lower_ty_relative_path(
150 &mut self,
151 ty: Ty<'db>,
152 res: Option<TypeNs>,
154 infer_args: bool,
155 ) -> (Ty<'db>, Option<TypeNs>) {
156 let remaining_segments = self.segments.len() - self.current_segment_idx;
157 match remaining_segments {
158 0 => (ty, res),
159 1 => {
160 (self.select_associated_type(res, infer_args), None)
162 }
163 _ => {
164 (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None)
166 }
167 }
168 }
169
170 pub(crate) fn lower_partly_resolved_path(
172 &mut self,
173 resolution: TypeNs,
174 infer_args: bool,
175 ) -> (Ty<'db>, Option<TypeNs>) {
176 let remaining_segments = self.segments.skip(self.current_segment_idx + 1);
177 tracing::debug!(?remaining_segments);
178 let rem_seg_len = remaining_segments.len();
179 tracing::debug!(?rem_seg_len);
180
181 let ty = match resolution {
182 TypeNs::TraitId(trait_) => {
183 let ty = match remaining_segments.len() {
184 1 => {
185 let trait_ref = self.lower_trait_ref_from_resolved_path(
186 trait_,
187 Ty::new_error(self.ctx.interner, ErrorGuaranteed),
188 false,
189 );
190 tracing::debug!(?trait_ref);
191 self.skip_resolved_segment();
192 let segment = self.current_or_prev_segment;
193 let trait_id = trait_ref.def_id.0;
194 let found =
195 trait_id.trait_items(self.ctx.db).associated_type_by_name(segment.name);
196
197 tracing::debug!(?found);
198 match found {
199 Some(associated_ty) => {
200 let substitution = self.substs_from_path_segment(
205 associated_ty.into(),
206 false,
207 None,
208 true,
209 );
210 let args = GenericArgs::new_from_iter(
211 self.ctx.interner,
212 trait_ref
213 .args
214 .iter()
215 .chain(substitution.iter().skip(trait_ref.args.len())),
216 );
217 Ty::new_alias(
218 self.ctx.interner,
219 AliasTyKind::Projection,
220 AliasTy::new_from_args(
221 self.ctx.interner,
222 associated_ty.into(),
223 args,
224 ),
225 )
226 }
227 None => {
228 Ty::new_error(self.ctx.interner, ErrorGuaranteed)
230 }
231 }
232 }
233 0 => {
234 stdx::never!("unexpected fully resolved trait path");
237 Ty::new_error(self.ctx.interner, ErrorGuaranteed)
238 }
239 _ => {
240 Ty::new_error(self.ctx.interner, ErrorGuaranteed)
242 }
243 };
244 return (ty, None);
245 }
246 TypeNs::GenericParam(param_id) => {
247 let generics = self.ctx.generics();
248 let idx = generics.type_or_const_param_idx(param_id.into());
249 match idx {
250 None => {
251 never!("no matching generics");
252 Ty::new_error(self.ctx.interner, ErrorGuaranteed)
253 }
254 Some(idx) => {
255 let (pidx, _param) = generics.iter().nth(idx).unwrap();
256 assert_eq!(pidx, param_id.into());
257 self.ctx.type_param(param_id, idx as u32)
258 }
259 }
260 }
261 TypeNs::SelfType(impl_id) => self.ctx.db.impl_self_ty(impl_id).skip_binder(),
262 TypeNs::AdtSelfType(adt) => {
263 let args = GenericArgs::identity_for_item(self.ctx.interner, adt.into());
264 Ty::new_adt(self.ctx.interner, adt, args)
265 }
266
267 TypeNs::AdtId(it) => self.lower_path_inner(it.into(), infer_args),
268 TypeNs::BuiltinType(it) => self.lower_path_inner(it.into(), infer_args),
269 TypeNs::TypeAliasId(it) => self.lower_path_inner(it.into(), infer_args),
270 TypeNs::EnumVariantId(_) | TypeNs::ModuleId(_) => {
272 return (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None);
273 }
274 };
275
276 tracing::debug!(?ty);
277
278 self.skip_resolved_segment();
279 self.lower_ty_relative_path(ty, Some(resolution), infer_args)
280 }
281
282 #[must_use]
284 fn handle_type_ns_resolution(&mut self, resolution: &TypeNs) -> bool {
285 let mut prohibit_generics_on_resolved = |reason| {
286 if self.current_or_prev_segment.args_and_bindings.is_some() {
287 let segment = self.current_segment_u32();
288 self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
289 segment,
290 reason,
291 });
292 }
293 };
294
295 match resolution {
296 TypeNs::SelfType(_) => {
297 prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
298 }
299 TypeNs::GenericParam(_) => {
300 prohibit_generics_on_resolved(GenericArgsProhibitedReason::TyParam)
301 }
302 TypeNs::AdtSelfType(_) => {
303 prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy);
304
305 if self.ctx.lowering_param_default.is_some() {
306 return false;
309 }
310 }
311 TypeNs::BuiltinType(_) => {
312 prohibit_generics_on_resolved(GenericArgsProhibitedReason::PrimitiveTy)
313 }
314 TypeNs::ModuleId(_) => {
315 prohibit_generics_on_resolved(GenericArgsProhibitedReason::Module)
316 }
317 TypeNs::AdtId(_)
318 | TypeNs::EnumVariantId(_)
319 | TypeNs::TypeAliasId(_)
320 | TypeNs::TraitId(_) => {}
321 }
322
323 true
324 }
325
326 pub(crate) fn resolve_path_in_type_ns_fully(&mut self) -> Option<TypeNs> {
327 let (res, unresolved) = self.resolve_path_in_type_ns()?;
328 if unresolved.is_some() {
329 return None;
330 }
331 Some(res)
332 }
333
334 #[tracing::instrument(skip(self), ret)]
335 pub(crate) fn resolve_path_in_type_ns(&mut self) -> Option<(TypeNs, Option<usize>)> {
336 let (resolution, remaining_index, _, prefix_info) =
337 self.ctx.resolver.resolve_path_in_type_ns_with_prefix_info(self.ctx.db, self.path)?;
338
339 let segments = self.segments;
340 if segments.is_empty() || matches!(self.path, Path::LangItem(..)) {
341 return Some((resolution, remaining_index));
343 }
344
345 let (module_segments, resolved_segment_idx, enum_segment) = match remaining_index {
346 None if prefix_info.enum_variant => {
347 (segments.strip_last_two(), segments.len() - 1, Some(segments.len() - 2))
348 }
349 None => (segments.strip_last(), segments.len() - 1, None),
350 Some(i) => (segments.take(i - 1), i - 1, None),
351 };
352
353 self.current_segment_idx = resolved_segment_idx;
354 self.current_or_prev_segment =
355 segments.get(resolved_segment_idx).expect("should have resolved segment");
356
357 for (i, mod_segment) in module_segments.iter().enumerate() {
358 if mod_segment.args_and_bindings.is_some() {
359 self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
360 segment: i as u32,
361 reason: GenericArgsProhibitedReason::Module,
362 });
363 }
364 }
365
366 if let Some(enum_segment) = enum_segment
367 && segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
368 && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
369 {
370 self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
371 segment: (enum_segment + 1) as u32,
372 reason: GenericArgsProhibitedReason::EnumVariant,
373 });
374 }
375
376 if !self.handle_type_ns_resolution(&resolution) {
377 return None;
378 }
379
380 Some((resolution, remaining_index))
381 }
382
383 pub(crate) fn resolve_path_in_value_ns(
384 &mut self,
385 hygiene_id: HygieneId,
386 ) -> Option<ResolveValueResult> {
387 let (res, prefix_info) = self.ctx.resolver.resolve_path_in_value_ns_with_prefix_info(
388 self.ctx.db,
389 self.path,
390 hygiene_id,
391 )?;
392
393 let segments = self.segments;
394 if segments.is_empty() || matches!(self.path, Path::LangItem(..)) {
395 return Some(res);
397 }
398
399 let (mod_segments, enum_segment, resolved_segment_idx) = match res {
400 ResolveValueResult::Partial(_, unresolved_segment, _) => {
401 (segments.take(unresolved_segment - 1), None, unresolved_segment - 1)
402 }
403 ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_), _)
404 if prefix_info.enum_variant =>
405 {
406 (segments.strip_last_two(), segments.len().checked_sub(2), segments.len() - 1)
407 }
408 ResolveValueResult::ValueNs(..) => (segments.strip_last(), None, segments.len() - 1),
409 };
410
411 self.current_segment_idx = resolved_segment_idx;
412 self.current_or_prev_segment =
413 segments.get(resolved_segment_idx).expect("should have resolved segment");
414
415 for (i, mod_segment) in mod_segments.iter().enumerate() {
416 if mod_segment.args_and_bindings.is_some() {
417 self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
418 segment: i as u32,
419 reason: GenericArgsProhibitedReason::Module,
420 });
421 }
422 }
423
424 if let Some(enum_segment) = enum_segment
425 && segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
426 && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
427 {
428 self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
429 segment: (enum_segment + 1) as u32,
430 reason: GenericArgsProhibitedReason::EnumVariant,
431 });
432 }
433
434 match &res {
435 ResolveValueResult::ValueNs(resolution, _) => {
436 let resolved_segment_idx = self.current_segment_u32();
437 let resolved_segment = self.current_or_prev_segment;
438
439 let mut prohibit_generics_on_resolved = |reason| {
440 if resolved_segment.args_and_bindings.is_some() {
441 self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
442 segment: resolved_segment_idx,
443 reason,
444 });
445 }
446 };
447
448 match resolution {
449 ValueNs::ImplSelf(_) => {
450 prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy);
451 }
452 ValueNs::GenericParam(_) => {
459 prohibit_generics_on_resolved(GenericArgsProhibitedReason::Const)
460 }
461 ValueNs::StaticId(_) => {
462 prohibit_generics_on_resolved(GenericArgsProhibitedReason::Static)
463 }
464 ValueNs::LocalBinding(_) => {
465 prohibit_generics_on_resolved(GenericArgsProhibitedReason::LocalVariable)
466 }
467 ValueNs::FunctionId(_)
468 | ValueNs::StructId(_)
469 | ValueNs::EnumVariantId(_)
470 | ValueNs::ConstId(_) => {}
471 }
472 }
473 ResolveValueResult::Partial(resolution, _, _) => {
474 if !self.handle_type_ns_resolution(resolution) {
475 return None;
476 }
477 }
478 };
479 Some(res)
480 }
481
482 #[tracing::instrument(skip(self), ret)]
483 fn select_associated_type(&mut self, res: Option<TypeNs>, infer_args: bool) -> Ty<'db> {
484 let interner = self.ctx.interner;
485 let Some(res) = res else {
486 return Ty::new_error(self.ctx.interner, ErrorGuaranteed);
487 };
488 let def = self.ctx.def;
489 let segment = self.current_or_prev_segment;
490 let assoc_name = segment.name;
491 let check_alias = |name: &Name, t: TraitRef<'db>, associated_ty: TypeAliasId| {
492 if name != assoc_name {
493 return None;
494 }
495
496 let substs =
501 self.substs_from_path_segment(associated_ty.into(), infer_args, None, true);
502
503 let substs = GenericArgs::new_from_iter(
504 interner,
505 t.args.iter().chain(substs.iter().skip(t.args.len())),
506 );
507
508 Some(Ty::new_alias(
509 interner,
510 AliasTyKind::Projection,
511 AliasTy::new(interner, associated_ty.into(), substs),
512 ))
513 };
514 named_associated_type_shorthand_candidates(
515 interner,
516 def,
517 res,
518 Some(assoc_name.clone()),
519 check_alias,
520 )
521 .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed))
522 }
523
524 fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty<'db> {
525 let generic_def = match typeable {
526 TyDefId::BuiltinType(builtinty) => {
527 return Ty::from_builtin_type(self.ctx.interner, builtinty);
528 }
529 TyDefId::AdtId(it) => it.into(),
530 TyDefId::TypeAliasId(it) => it.into(),
531 };
532 let args = self.substs_from_path_segment(generic_def, infer_args, None, false);
533 let ty = ty_query(self.ctx.db, typeable);
534 ty.instantiate(self.ctx.interner, args)
535 }
536
537 pub(crate) fn substs_from_path(
540 &mut self,
541 resolved: ValueTyDefId,
545 infer_args: bool,
546 lowering_assoc_type_generics: bool,
547 ) -> GenericArgs<'db> {
548 let interner = self.ctx.interner;
549 let prev_current_segment_idx = self.current_segment_idx;
550 let prev_current_segment = self.current_or_prev_segment;
551
552 let generic_def = match resolved {
553 ValueTyDefId::FunctionId(it) => it.into(),
554 ValueTyDefId::StructId(it) => it.into(),
555 ValueTyDefId::UnionId(it) => it.into(),
556 ValueTyDefId::ConstId(it) => it.into(),
557 ValueTyDefId::StaticId(_) => {
558 return GenericArgs::new_from_iter(interner, []);
559 }
560 ValueTyDefId::EnumVariantId(var) => {
561 let penultimate_idx = self.current_segment_idx.wrapping_sub(1);
574 let penultimate = self.segments.get(penultimate_idx);
575 if let Some(penultimate) = penultimate
576 && self.current_or_prev_segment.args_and_bindings.is_none()
577 && penultimate.args_and_bindings.is_some()
578 {
579 self.current_segment_idx = penultimate_idx;
580 self.current_or_prev_segment = penultimate;
581 }
582 var.lookup(self.ctx.db).parent.into()
583 }
584 };
585 let result = self.substs_from_path_segment(
586 generic_def,
587 infer_args,
588 None,
589 lowering_assoc_type_generics,
590 );
591 self.current_segment_idx = prev_current_segment_idx;
592 self.current_or_prev_segment = prev_current_segment;
593 result
594 }
595
596 pub(crate) fn substs_from_path_segment(
597 &mut self,
598 def: GenericDefId,
599 infer_args: bool,
600 explicit_self_ty: Option<Ty<'db>>,
601 lowering_assoc_type_generics: bool,
602 ) -> GenericArgs<'db> {
603 let old_lifetime_elision = self.ctx.lifetime_elision.clone();
604
605 if let Some(args) = self.current_or_prev_segment.args_and_bindings
606 && args.parenthesized != GenericArgsParentheses::No
607 {
608 let prohibit_parens = match def {
609 GenericDefId::TraitId(trait_) => {
610 let is_rtn = args.parenthesized == GenericArgsParentheses::ReturnTypeNotation;
612 let is_fn_trait = self
613 .ctx
614 .db
615 .trait_signature(trait_)
616 .flags
617 .contains(TraitFlags::RUSTC_PAREN_SUGAR);
618 is_rtn || !is_fn_trait
619 }
620 _ => true,
621 };
622
623 if prohibit_parens {
624 let segment = self.current_segment_u32();
625 self.on_diagnostic(
626 PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
627 );
628
629 return unknown_subst(self.ctx.interner, def);
630 }
631
632 self.ctx.lifetime_elision =
634 LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false };
635 }
636
637 let result = self.substs_from_args_and_bindings(
638 self.current_or_prev_segment.args_and_bindings,
639 def,
640 infer_args,
641 explicit_self_ty,
642 PathGenericsSource::Segment(self.current_segment_u32()),
643 lowering_assoc_type_generics,
644 self.ctx.lifetime_elision.clone(),
645 );
646 self.ctx.lifetime_elision = old_lifetime_elision;
647 result
648 }
649
650 pub(super) fn substs_from_args_and_bindings(
651 &mut self,
652 args_and_bindings: Option<&HirGenericArgs>,
653 def: GenericDefId,
654 infer_args: bool,
655 explicit_self_ty: Option<Ty<'db>>,
656 generics_source: PathGenericsSource,
657 lowering_assoc_type_generics: bool,
658 lifetime_elision: LifetimeElisionKind<'db>,
659 ) -> GenericArgs<'db> {
660 struct LowererCtx<'a, 'b, 'c, 'db> {
661 ctx: &'a mut PathLoweringContext<'b, 'c, 'db>,
662 generics_source: PathGenericsSource,
663 }
664
665 impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, '_, '_, 'db> {
666 fn report_len_mismatch(
667 &mut self,
668 def: GenericDefId,
669 provided_count: u32,
670 expected_count: u32,
671 kind: IncorrectGenericsLenKind,
672 ) {
673 self.ctx.on_diagnostic(PathLoweringDiagnostic::IncorrectGenericsLen {
674 generics_source: self.generics_source,
675 provided_count,
676 expected_count,
677 kind,
678 def,
679 });
680 }
681
682 fn report_arg_mismatch(
683 &mut self,
684 param_id: GenericParamId,
685 arg_idx: u32,
686 has_self_arg: bool,
687 ) {
688 self.ctx.on_diagnostic(PathLoweringDiagnostic::IncorrectGenericsOrder {
689 generics_source: self.generics_source,
690 param_id,
691 arg_idx,
692 has_self_arg,
693 });
694 }
695
696 fn provided_kind(
697 &mut self,
698 param_id: GenericParamId,
699 param: GenericParamDataRef<'_>,
700 arg: &HirGenericArg,
701 ) -> GenericArg<'db> {
702 match (param, *arg) {
703 (
704 GenericParamDataRef::LifetimeParamData(_),
705 HirGenericArg::Lifetime(lifetime),
706 ) => self.ctx.ctx.lower_lifetime(lifetime).into(),
707 (GenericParamDataRef::TypeParamData(_), HirGenericArg::Type(type_ref)) => {
708 self.ctx.ctx.lower_ty(type_ref).into()
709 }
710 (GenericParamDataRef::ConstParamData(_), HirGenericArg::Const(konst)) => {
711 let GenericParamId::ConstParamId(const_id) = param_id else {
712 unreachable!("non-const param ID for const param");
713 };
714 self.ctx
715 .ctx
716 .lower_const(konst, const_param_ty_query(self.ctx.ctx.db, const_id))
717 .into()
718 }
719 _ => unreachable!("unmatching param kinds were passed to `provided_kind()`"),
720 }
721 }
722
723 fn provided_type_like_const(
724 &mut self,
725 const_ty: Ty<'db>,
726 arg: TypeLikeConst<'_>,
727 ) -> Const<'db> {
728 match arg {
729 TypeLikeConst::Path(path) => self.ctx.ctx.lower_path_as_const(path, const_ty),
730 TypeLikeConst::Infer => unknown_const(const_ty),
731 }
732 }
733
734 fn inferred_kind(
735 &mut self,
736 def: GenericDefId,
737 param_id: GenericParamId,
738 param: GenericParamDataRef<'_>,
739 infer_args: bool,
740 preceding_args: &[GenericArg<'db>],
741 ) -> GenericArg<'db> {
742 let default =
743 || {
744 self.ctx.ctx.db.generic_defaults(def).get(preceding_args.len()).map(
745 |default| default.instantiate(self.ctx.ctx.interner, preceding_args),
746 )
747 };
748 match param {
749 GenericParamDataRef::LifetimeParamData(_) => {
750 Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed))
751 .into()
752 }
753 GenericParamDataRef::TypeParamData(param) => {
754 if !infer_args
755 && param.default.is_some()
756 && let Some(default) = default()
757 {
758 return default;
759 }
760 Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into()
761 }
762 GenericParamDataRef::ConstParamData(param) => {
763 if !infer_args
764 && param.default.is_some()
765 && let Some(default) = default()
766 {
767 return default;
768 }
769 let GenericParamId::ConstParamId(const_id) = param_id else {
770 unreachable!("non-const param ID for const param");
771 };
772 unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id))
773 }
774 }
775 }
776
777 fn parent_arg(&mut self, _param_idx: u32, param_id: GenericParamId) -> GenericArg<'db> {
778 match param_id {
779 GenericParamId::TypeParamId(_) => {
780 Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into()
781 }
782 GenericParamId::ConstParamId(const_id) => {
783 unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id))
784 }
785 GenericParamId::LifetimeParamId(_) => {
786 Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed))
787 .into()
788 }
789 }
790 }
791
792 fn report_elided_lifetimes_in_path(
793 &mut self,
794 def: GenericDefId,
795 expected_count: u32,
796 hard_error: bool,
797 ) {
798 self.ctx.on_diagnostic(PathLoweringDiagnostic::ElidedLifetimesInPath {
799 generics_source: self.generics_source,
800 def,
801 expected_count,
802 hard_error,
803 });
804 }
805
806 fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32) {
807 self.ctx.on_diagnostic(PathLoweringDiagnostic::ElisionFailure {
808 generics_source: self.generics_source,
809 def,
810 expected_count,
811 });
812 }
813
814 fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32) {
815 self.ctx.on_diagnostic(PathLoweringDiagnostic::MissingLifetime {
816 generics_source: self.generics_source,
817 def,
818 expected_count,
819 });
820 }
821 }
822
823 substs_from_args_and_bindings(
824 self.ctx.db,
825 self.ctx.store,
826 args_and_bindings,
827 def,
828 infer_args,
829 lifetime_elision,
830 lowering_assoc_type_generics,
831 explicit_self_ty,
832 &mut LowererCtx { ctx: self, generics_source },
833 )
834 }
835
836 pub(crate) fn lower_trait_ref_from_resolved_path(
837 &mut self,
838 resolved: TraitId,
839 explicit_self_ty: Ty<'db>,
840 infer_args: bool,
841 ) -> TraitRef<'db> {
842 let args = self.trait_ref_substs_from_path(resolved, explicit_self_ty, infer_args);
843 TraitRef::new_from_args(self.ctx.interner, resolved.into(), args)
844 }
845
846 fn trait_ref_substs_from_path(
847 &mut self,
848 resolved: TraitId,
849 explicit_self_ty: Ty<'db>,
850 infer_args: bool,
851 ) -> GenericArgs<'db> {
852 self.substs_from_path_segment(resolved.into(), infer_args, Some(explicit_self_ty), false)
853 }
854
855 pub(super) fn assoc_type_bindings_from_type_bound<'c>(
856 mut self,
857 trait_ref: TraitRef<'db>,
858 ) -> Option<impl Iterator<Item = Clause<'db>> + use<'a, 'b, 'c, 'db>> {
859 let interner = self.ctx.interner;
860 self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| {
861 args_and_bindings.bindings.iter().enumerate().flat_map(move |(binding_idx, binding)| {
862 let found = associated_type_by_name_including_super_traits(
863 self.ctx.db,
864 trait_ref,
865 &binding.name,
866 );
867 let (super_trait_ref, associated_ty) = match found {
868 None => return SmallVec::new(),
869 Some(t) => t,
870 };
871 let args =
872 self.with_lifetime_elision(LifetimeElisionKind::AnonymousReportError, |this| {
873 this.substs_from_args_and_bindings(
878 binding.args.as_ref(),
879 associated_ty.into(),
880 false, Some(super_trait_ref.self_ty()),
882 PathGenericsSource::AssocType {
883 segment: this.current_segment_u32(),
884 assoc_type: binding_idx as u32,
885 },
886 false,
887 this.ctx.lifetime_elision.clone(),
888 )
889 });
890 let args = GenericArgs::new_from_iter(
891 interner,
892 super_trait_ref.args.iter().chain(args.iter().skip(super_trait_ref.args.len())),
893 );
894 let projection_term =
895 AliasTerm::new_from_args(interner, associated_ty.into(), args);
896 let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity(
897 binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
898 );
899 if let Some(type_ref) = binding.type_ref {
900 let lifetime_elision =
901 if args_and_bindings.parenthesized == GenericArgsParentheses::ParenSugar {
902 LifetimeElisionKind::for_fn_ret(self.ctx.interner)
904 } else {
905 self.ctx.lifetime_elision.clone()
906 };
907 self.with_lifetime_elision(lifetime_elision, |this| {
908 match (&this.ctx.store[type_ref], this.ctx.impl_trait_mode.mode) {
909 (TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (),
910 (
911 _,
912 ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque,
913 ) => {
914 let ty = this.ctx.lower_ty(type_ref);
915 let pred = Clause(Predicate::new(
916 interner,
917 Binder::dummy(rustc_type_ir::PredicateKind::Clause(
918 rustc_type_ir::ClauseKind::Projection(
919 ProjectionPredicate {
920 projection_term,
921 term: ty.into(),
922 },
923 ),
924 )),
925 ));
926 predicates.push(pred);
927 }
928 }
929 })
930 }
931 for bound in binding.bounds.iter() {
932 predicates.extend(self.ctx.lower_type_bound(
933 bound,
934 Ty::new_alias(
935 self.ctx.interner,
936 AliasTyKind::Projection,
937 AliasTy::new_from_args(self.ctx.interner, associated_ty.into(), args),
938 ),
939 false,
940 ));
941 }
942 predicates
943 })
944 })
945 }
946}
947
948pub(crate) enum TypeLikeConst<'a> {
950 Infer,
951 Path(&'a Path),
952}
953
954pub(crate) trait GenericArgsLowerer<'db> {
955 fn report_elided_lifetimes_in_path(
956 &mut self,
957 def: GenericDefId,
958 expected_count: u32,
959 hard_error: bool,
960 );
961
962 fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32);
963
964 fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32);
965
966 fn report_len_mismatch(
967 &mut self,
968 def: GenericDefId,
969 provided_count: u32,
970 expected_count: u32,
971 kind: IncorrectGenericsLenKind,
972 );
973
974 fn report_arg_mismatch(&mut self, param_id: GenericParamId, arg_idx: u32, has_self_arg: bool);
975
976 fn provided_kind(
977 &mut self,
978 param_id: GenericParamId,
979 param: GenericParamDataRef<'_>,
980 arg: &HirGenericArg,
981 ) -> GenericArg<'db>;
982
983 fn provided_type_like_const(&mut self, const_ty: Ty<'db>, arg: TypeLikeConst<'_>)
984 -> Const<'db>;
985
986 fn inferred_kind(
987 &mut self,
988 def: GenericDefId,
989 param_id: GenericParamId,
990 param: GenericParamDataRef<'_>,
991 infer_args: bool,
992 preceding_args: &[GenericArg<'db>],
993 ) -> GenericArg<'db>;
994
995 fn parent_arg(&mut self, param_idx: u32, param_id: GenericParamId) -> GenericArg<'db>;
996}
997
998fn check_generic_args_len<'db>(
1000 args_and_bindings: Option<&HirGenericArgs>,
1001 def: GenericDefId,
1002 def_generics: &Generics,
1003 infer_args: bool,
1004 lifetime_elision: &LifetimeElisionKind<'db>,
1005 lowering_assoc_type_generics: bool,
1006 ctx: &mut impl GenericArgsLowerer<'db>,
1007) -> bool {
1008 let mut had_error = false;
1009
1010 let (mut provided_lifetimes_count, mut provided_types_and_consts_count) = (0usize, 0usize);
1011 if let Some(args_and_bindings) = args_and_bindings {
1012 let args_no_self = &args_and_bindings.args[usize::from(args_and_bindings.has_self_type)..];
1013 for arg in args_no_self {
1014 match arg {
1015 HirGenericArg::Lifetime(_) => provided_lifetimes_count += 1,
1016 HirGenericArg::Type(_) | HirGenericArg::Const(_) => {
1017 provided_types_and_consts_count += 1
1018 }
1019 }
1020 }
1021 }
1022
1023 let lifetime_args_len = def_generics.len_lifetimes_self();
1024 if provided_lifetimes_count == 0
1025 && lifetime_args_len > 0
1026 && (!lowering_assoc_type_generics || infer_args)
1027 {
1028 match lifetime_elision {
1031 &LifetimeElisionKind::AnonymousCreateParameter { report_in_path } => {
1032 ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, report_in_path);
1033 had_error |= report_in_path;
1034 }
1035 LifetimeElisionKind::AnonymousReportError => {
1036 ctx.report_missing_lifetime(def, lifetime_args_len as u32);
1037 had_error = true
1038 }
1039 LifetimeElisionKind::ElisionFailure => {
1040 ctx.report_elision_failure(def, lifetime_args_len as u32);
1041 had_error = true;
1042 }
1043 LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
1044 }
1046 LifetimeElisionKind::Elided(_) => {
1047 ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, false);
1048 }
1049 LifetimeElisionKind::Infer => {
1050 }
1052 }
1053 } else if lifetime_args_len != provided_lifetimes_count {
1054 ctx.report_len_mismatch(
1055 def,
1056 provided_lifetimes_count as u32,
1057 lifetime_args_len as u32,
1058 IncorrectGenericsLenKind::Lifetimes,
1059 );
1060 had_error = true;
1061 }
1062
1063 let defaults_count =
1064 def_generics.iter_self_type_or_consts().filter(|(_, param)| param.has_default()).count();
1065 let named_type_and_const_params_count = def_generics
1066 .iter_self_type_or_consts()
1067 .filter(|(_, param)| match param {
1068 TypeOrConstParamData::TypeParamData(param) => {
1069 param.provenance == TypeParamProvenance::TypeParamList
1070 }
1071 TypeOrConstParamData::ConstParamData(_) => true,
1072 })
1073 .count();
1074 let expected_max = named_type_and_const_params_count;
1075 let expected_min =
1076 if infer_args { 0 } else { named_type_and_const_params_count - defaults_count };
1077 if provided_types_and_consts_count < expected_min
1078 || expected_max < provided_types_and_consts_count
1079 {
1080 ctx.report_len_mismatch(
1081 def,
1082 provided_types_and_consts_count as u32,
1083 named_type_and_const_params_count as u32,
1084 IncorrectGenericsLenKind::TypesAndConsts,
1085 );
1086 had_error = true;
1087 }
1088
1089 had_error
1090}
1091
1092pub(crate) fn substs_from_args_and_bindings<'db>(
1093 db: &'db dyn HirDatabase,
1094 store: &ExpressionStore,
1095 args_and_bindings: Option<&HirGenericArgs>,
1096 def: GenericDefId,
1097 mut infer_args: bool,
1098 lifetime_elision: LifetimeElisionKind<'db>,
1099 lowering_assoc_type_generics: bool,
1100 explicit_self_ty: Option<Ty<'db>>,
1101 ctx: &mut impl GenericArgsLowerer<'db>,
1102) -> GenericArgs<'db> {
1103 let interner = DbInterner::new_no_crate(db);
1104
1105 tracing::debug!(?args_and_bindings);
1106
1107 let def_generics = generics(db, def);
1113 let args_slice = args_and_bindings.map(|it| &*it.args).unwrap_or_default();
1114
1115 let has_non_lifetime_args =
1117 args_slice.iter().any(|arg| !matches!(arg, HirGenericArg::Lifetime(_)));
1118 infer_args &= !has_non_lifetime_args;
1119
1120 let had_count_error = check_generic_args_len(
1121 args_and_bindings,
1122 def,
1123 &def_generics,
1124 infer_args,
1125 &lifetime_elision,
1126 lowering_assoc_type_generics,
1127 ctx,
1128 );
1129
1130 let mut substs = Vec::with_capacity(def_generics.len());
1131
1132 substs.extend(
1133 def_generics.iter_parent_id().enumerate().map(|(idx, id)| ctx.parent_arg(idx as u32, id)),
1134 );
1135
1136 let mut args = args_slice.iter().enumerate().peekable();
1137 let mut params = def_generics.iter_self().peekable();
1138
1139 let mut force_infer_lt = None;
1144
1145 let has_self_arg = args_and_bindings.is_some_and(|it| it.has_self_type);
1146 if let Some(&(
1149 self_param_id,
1150 self_param @ GenericParamDataRef::TypeParamData(TypeParamData {
1151 provenance: TypeParamProvenance::TraitSelf,
1152 ..
1153 }),
1154 )) = params.peek()
1155 {
1156 let self_ty = if has_self_arg {
1157 let (_, self_ty) = args.next().expect("has_self_type=true, should have Self type");
1158 ctx.provided_kind(self_param_id, self_param, self_ty)
1159 } else {
1160 explicit_self_ty.map(|it| it.into()).unwrap_or_else(|| {
1161 ctx.inferred_kind(def, self_param_id, self_param, infer_args, &substs)
1162 })
1163 };
1164 params.next();
1165 substs.push(self_ty);
1166 }
1167
1168 loop {
1169 match (args.peek(), params.peek()) {
1174 (Some(&(arg_idx, arg)), Some(&(param_id, param))) => match (arg, param) {
1175 (HirGenericArg::Type(_), GenericParamDataRef::TypeParamData(type_param))
1176 if type_param.provenance == TypeParamProvenance::ArgumentImplTrait =>
1177 {
1178 substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs));
1181 params.next();
1182 }
1183 (HirGenericArg::Lifetime(_), GenericParamDataRef::LifetimeParamData(_))
1184 | (HirGenericArg::Type(_), GenericParamDataRef::TypeParamData(_))
1185 | (HirGenericArg::Const(_), GenericParamDataRef::ConstParamData(_)) => {
1186 substs.push(ctx.provided_kind(param_id, param, arg));
1187 args.next();
1188 params.next();
1189 }
1190 (
1191 HirGenericArg::Type(_) | HirGenericArg::Const(_),
1192 GenericParamDataRef::LifetimeParamData(_),
1193 ) => {
1194 substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs));
1197 params.next();
1198 force_infer_lt = Some((arg_idx as u32, param_id));
1199 }
1200 (HirGenericArg::Type(type_ref), GenericParamDataRef::ConstParamData(_)) => {
1201 if let Some(konst) = type_looks_like_const(store, *type_ref) {
1202 let GenericParamId::ConstParamId(param_id) = param_id else {
1203 panic!("unmatching param kinds");
1204 };
1205 let const_ty = const_param_ty_query(db, param_id);
1206 substs.push(ctx.provided_type_like_const(const_ty, konst).into());
1207 args.next();
1208 params.next();
1209 } else {
1210 if !had_count_error {
1212 ctx.report_arg_mismatch(param_id, arg_idx as u32, has_self_arg);
1213 }
1214 while args.next().is_some() {}
1215 }
1216 }
1217 _ => {
1218 if !had_count_error {
1223 ctx.report_arg_mismatch(param_id, arg_idx as u32, has_self_arg);
1224 }
1225
1226 while args.next().is_some() {}
1232 }
1233 },
1234
1235 (Some(&(_, arg)), None) => {
1236 if !had_count_error {
1244 assert!(
1245 matches!(arg, HirGenericArg::Lifetime(_)),
1246 "the only possible situation here is incorrect lifetime order"
1247 );
1248 let (provided_arg_idx, param_id) =
1249 force_infer_lt.expect("lifetimes ought to have been inferred");
1250 ctx.report_arg_mismatch(param_id, provided_arg_idx, has_self_arg);
1251 }
1252
1253 break;
1254 }
1255
1256 (None, Some(&(param_id, param))) => {
1257 let param = if let GenericParamId::LifetimeParamId(_) = param_id {
1259 match &lifetime_elision {
1260 LifetimeElisionKind::ElisionFailure
1261 | LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }
1262 | LifetimeElisionKind::AnonymousReportError => {
1263 assert!(had_count_error);
1264 ctx.inferred_kind(def, param_id, param, infer_args, &substs)
1265 }
1266 LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
1267 Region::new_static(interner).into()
1268 }
1269 LifetimeElisionKind::Elided(lifetime) => (*lifetime).into(),
1270 LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }
1271 | LifetimeElisionKind::Infer => {
1272 ctx.inferred_kind(def, param_id, param, infer_args, &substs)
1275 }
1276 }
1277 } else {
1278 ctx.inferred_kind(def, param_id, param, infer_args, &substs)
1279 };
1280 substs.push(param);
1281 params.next();
1282 }
1283
1284 (None, None) => break,
1285 }
1286 }
1287
1288 GenericArgs::new_from_iter(interner, substs)
1289}
1290
1291fn type_looks_like_const(
1292 store: &ExpressionStore,
1293 type_ref: TypeRefId,
1294) -> Option<TypeLikeConst<'_>> {
1295 let type_ref = &store[type_ref];
1301 match type_ref {
1302 TypeRef::Path(path) => Some(TypeLikeConst::Path(path)),
1303 TypeRef::Placeholder => Some(TypeLikeConst::Infer),
1304 _ => None,
1305 }
1306}
1307
1308fn unknown_subst<'db>(interner: DbInterner<'db>, def: impl Into<GenericDefId>) -> GenericArgs<'db> {
1309 let params = generics(interner.db(), def.into());
1310 GenericArgs::new_from_iter(
1311 interner,
1312 params.iter_id().map(|id| match id {
1313 GenericParamId::TypeParamId(_) => Ty::new_error(interner, ErrorGuaranteed).into(),
1314 GenericParamId::ConstParamId(id) => {
1315 unknown_const_as_generic(const_param_ty_query(interner.db(), id))
1316 }
1317 GenericParamId::LifetimeParamId(_) => Region::error(interner).into(),
1318 }),
1319 )
1320}