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