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 trait_ref
218 .args
219 .iter()
220 .chain(substitution.iter().skip(trait_ref.args.len())),
221 );
222 Ty::new_alias(
223 self.ctx.interner,
224 AliasTy::new_from_args(
225 self.ctx.interner,
226 AliasTyKind::Projection { def_id: associated_ty.into() },
227 args,
228 ),
229 )
230 }
231 None => {
232 self.ctx.types.types.error
234 }
235 }
236 }
237 0 => {
238 stdx::never!("unexpected fully resolved trait path");
241 self.ctx.types.types.error
242 }
243 _ => {
244 self.ctx.types.types.error
246 }
247 };
248 return (ty, None);
249 }
250 TypeNs::GenericParam(param_id) => {
251 let generics = self.ctx.generics();
252 let idx = generics.type_or_const_param_idx(param_id.into());
253 self.ctx.type_param(param_id, idx)
254 }
255 TypeNs::SelfType(impl_id) => self.ctx.db.impl_self_ty(impl_id).skip_binder(),
256 TypeNs::AdtSelfType(adt) => {
257 let args = GenericArgs::identity_for_item(self.ctx.interner, adt.into());
258 Ty::new_adt(self.ctx.interner, adt, args)
259 }
260
261 TypeNs::AdtId(it) => self.lower_path_inner(it.into(), infer_args, span),
262 TypeNs::BuiltinType(it) => self.lower_path_inner(it.into(), infer_args, span),
263 TypeNs::TypeAliasId(it) => self.lower_path_inner(it.into(), infer_args, span),
264 TypeNs::EnumVariantId(_) | TypeNs::ModuleId(_) => {
266 return (self.ctx.types.types.error, None);
267 }
268 };
269
270 tracing::debug!(?ty);
271
272 self.skip_resolved_segment();
273 self.lower_ty_relative_path(ty, Some(resolution), infer_args, span)
274 }
275
276 #[must_use]
278 fn handle_type_ns_resolution(&mut self, resolution: &TypeNs) -> bool {
279 let mut prohibit_generics_on_resolved = |reason| {
280 if self.current_or_prev_segment.args_and_bindings.is_some() {
281 let segment = self.current_segment_u32();
282 self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
283 segment,
284 reason,
285 });
286 }
287 };
288
289 match resolution {
290 TypeNs::SelfType(_) => {
291 prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
292 }
293 TypeNs::GenericParam(_) => {
294 prohibit_generics_on_resolved(GenericArgsProhibitedReason::TyParam)
295 }
296 TypeNs::AdtSelfType(_) => {
297 prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy);
298
299 if self.ctx.forbid_params_after.is_some()
300 && self.ctx.forbid_params_after_reason
301 == ForbidParamsAfterReason::LoweringParamDefault
302 {
303 let segment = self.current_segment_u32();
305 self.on_diagnostic(PathLoweringDiagnostic::GenericDefaultRefersToSelf {
306 segment,
307 });
308 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(_)) if prefix_info.enum_variant => {
404 (segments.strip_last_two(), segments.len().checked_sub(2), segments.len() - 1)
405 }
406 ResolveValueResult::ValueNs(..) => (segments.strip_last(), None, segments.len() - 1),
407 };
408
409 self.current_segment_idx = resolved_segment_idx;
410 self.current_or_prev_segment =
411 segments.get(resolved_segment_idx).expect("should have resolved segment");
412
413 for (i, mod_segment) in mod_segments.iter().enumerate() {
414 if mod_segment.args_and_bindings.is_some() {
415 self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
416 segment: i as u32,
417 reason: GenericArgsProhibitedReason::Module,
418 });
419 }
420 }
421
422 if let Some(enum_segment) = enum_segment
423 && segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
424 && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
425 {
426 self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
427 segment: (enum_segment + 1) as u32,
428 reason: GenericArgsProhibitedReason::EnumVariant,
429 });
430 }
431
432 match &res {
433 ResolveValueResult::ValueNs(resolution) => {
434 let resolved_segment_idx = self.current_segment_u32();
435 let resolved_segment = self.current_or_prev_segment;
436
437 let mut prohibit_generics_on_resolved = |reason| {
438 if resolved_segment.args_and_bindings.is_some() {
439 self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
440 segment: resolved_segment_idx,
441 reason,
442 });
443 }
444 };
445
446 match resolution {
447 ValueNs::ImplSelf(_) => {
448 prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy);
449 }
450 ValueNs::GenericParam(_) => {
457 prohibit_generics_on_resolved(GenericArgsProhibitedReason::Const)
458 }
459 ValueNs::StaticId(_) => {
460 prohibit_generics_on_resolved(GenericArgsProhibitedReason::Static)
461 }
462 ValueNs::LocalBinding(_) => {
463 prohibit_generics_on_resolved(GenericArgsProhibitedReason::LocalVariable)
464 }
465 ValueNs::FunctionId(_)
466 | ValueNs::StructId(_)
467 | ValueNs::EnumVariantId(_)
468 | ValueNs::ConstId(_) => {}
469 }
470 }
471 ResolveValueResult::Partial(resolution, _) => {
472 if !self.handle_type_ns_resolution(resolution) {
473 return None;
474 }
475 }
476 };
477 Some(res)
478 }
479
480 #[tracing::instrument(skip(self), ret)]
481 fn select_associated_type(
482 &mut self,
483 res: Option<TypeNs>,
484 infer_args: bool,
485 span: Span,
486 ) -> Ty<'db> {
487 let interner = self.ctx.interner;
488 let db = self.ctx.db;
489 let def = self.ctx.generic_def;
490 let segment = self.current_or_prev_segment;
491 let assoc_name = segment.name;
492 let (assoc_type, trait_args) = match res {
493 Some(TypeNs::GenericParam(param)) => {
494 let AssocTypeShorthandResolution::Resolved(assoc_type) =
495 super::resolve_type_param_assoc_type_shorthand(
496 db,
497 def,
498 param,
499 assoc_name.clone(),
500 )
501 else {
502 return self.ctx.types.types.error;
504 };
505 assoc_type
506 .get_with(|(assoc_type, trait_args)| (*assoc_type, trait_args.as_ref()))
507 .skip_binder()
508 }
509 Some(TypeNs::SelfType(impl_)) => {
510 let Some(impl_trait) = db.impl_trait(impl_) else {
511 return self.ctx.types.types.error;
512 };
513 let impl_trait = impl_trait.instantiate_identity().skip_norm_wip();
514 let AssocTypeShorthandResolution::Resolved(assoc_type) =
516 super::resolve_type_param_assoc_type_shorthand(
517 db,
518 impl_trait.def_id.0.into(),
519 TypeParamId::trait_self(impl_trait.def_id.0),
520 assoc_name.clone(),
521 )
522 else {
523 return self.ctx.types.types.error;
525 };
526 let (assoc_type, trait_args) = assoc_type
527 .get_with(|(assoc_type, trait_args)| (*assoc_type, trait_args.as_ref()))
528 .skip_binder();
529 (
530 assoc_type,
531 EarlyBinder::bind(trait_args)
532 .instantiate(interner, impl_trait.args)
533 .skip_norm_wip(),
534 )
535 }
536 _ => return self.ctx.types.types.error,
537 };
538
539 let substs = self.substs_from_path_segment(assoc_type.into(), infer_args, None, true, span);
544
545 let substs = GenericArgs::new_from_iter(
546 trait_args.iter().chain(substs.iter().skip(trait_args.len())),
547 );
548
549 Ty::new_projection_from_args(interner, assoc_type.into(), substs)
550 }
551
552 fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool, span: Span) -> Ty<'db> {
553 let generic_def = match typeable {
554 TyDefId::BuiltinType(builtinty) => {
555 return Ty::from_builtin_type(self.ctx.interner, builtinty);
556 }
557 TyDefId::AdtId(it) => it.into(),
558 TyDefId::TypeAliasId(it) => it.into(),
559 };
560 let args = self.substs_from_path_segment(generic_def, infer_args, None, false, span);
561 let ty = ty_query(self.ctx.db, typeable);
562 ty.instantiate(self.ctx.interner, args).skip_norm_wip()
563 }
564
565 pub(crate) fn substs_from_path(
568 &mut self,
569 resolved: ValueTyDefId,
573 infer_args: bool,
574 lowering_assoc_type_generics: bool,
575 span: Span,
576 ) -> GenericArgs<'db> {
577 let prev_current_segment_idx = self.current_segment_idx;
578 let prev_current_segment = self.current_or_prev_segment;
579
580 let generic_def = match resolved {
581 ValueTyDefId::FunctionId(it) => it.into(),
582 ValueTyDefId::StructId(it) => it.into(),
583 ValueTyDefId::UnionId(it) => it.into(),
584 ValueTyDefId::ConstId(it) => it.into(),
585 ValueTyDefId::StaticId(_) => {
586 return GenericArgs::empty();
587 }
588 ValueTyDefId::EnumVariantId(var) => {
589 let penultimate_idx = self.current_segment_idx.wrapping_sub(1);
602 let penultimate = self.segments.get(penultimate_idx);
603 if let Some(penultimate) = penultimate
604 && self.current_or_prev_segment.args_and_bindings.is_none()
605 && penultimate.args_and_bindings.is_some()
606 {
607 self.current_segment_idx = penultimate_idx;
608 self.current_or_prev_segment = penultimate;
609 }
610 var.lookup(self.ctx.db).parent.into()
611 }
612 };
613 let result = self.substs_from_path_segment(
614 generic_def,
615 infer_args,
616 None,
617 lowering_assoc_type_generics,
618 span,
619 );
620 self.current_segment_idx = prev_current_segment_idx;
621 self.current_or_prev_segment = prev_current_segment;
622 result
623 }
624
625 pub(crate) fn substs_from_path_segment(
626 &mut self,
627 def: GenericDefId,
628 infer_args: bool,
629 explicit_self_ty: Option<Ty<'db>>,
630 lowering_assoc_type_generics: bool,
631 span: Span,
632 ) -> GenericArgs<'db> {
633 let old_lifetime_elision = self.ctx.lifetime_elision;
634
635 if let Some(args) = self.current_or_prev_segment.args_and_bindings
636 && args.parenthesized != GenericArgsParentheses::No
637 {
638 let prohibit_parens = match def {
639 GenericDefId::TraitId(trait_) => {
640 let is_rtn = args.parenthesized == GenericArgsParentheses::ReturnTypeNotation;
642 let is_fn_trait = TraitSignature::of(self.ctx.db, trait_)
643 .flags
644 .contains(TraitFlags::RUSTC_PAREN_SUGAR);
645 is_rtn || !is_fn_trait
646 }
647 _ => true,
648 };
649
650 if prohibit_parens {
651 let segment = self.current_segment_u32();
652 self.on_diagnostic(
653 PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
654 );
655
656 return GenericArgs::error_for_item(self.ctx.interner, def.into());
657 }
658
659 self.ctx.lifetime_elision =
661 LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false };
662 }
663
664 let result = self.substs_from_args_and_bindings(
665 self.current_or_prev_segment.args_and_bindings,
666 def,
667 infer_args,
668 explicit_self_ty,
669 PathGenericsSource::Segment(self.current_segment_u32()),
670 lowering_assoc_type_generics,
671 self.ctx.lifetime_elision,
672 span,
673 );
674 self.ctx.lifetime_elision = old_lifetime_elision;
675 result
676 }
677
678 pub(super) fn substs_from_args_and_bindings(
679 &mut self,
680 args_and_bindings: Option<&HirGenericArgs>,
681 def: GenericDefId,
682 infer_args: bool,
683 explicit_self_ty: Option<Ty<'db>>,
684 generics_source: PathGenericsSource,
685 lowering_assoc_type_generics: bool,
686 lifetime_elision: LifetimeElisionKind<'db>,
687 span: Span,
688 ) -> GenericArgs<'db> {
689 struct LowererCtx<'a, 'b, 'c, 'db> {
690 ctx: &'a mut PathLoweringContext<'b, 'c, 'db>,
691 generics_source: PathGenericsSource,
692 span: Span,
693 }
694
695 impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, '_, '_, 'db> {
696 fn report_len_mismatch(
697 &mut self,
698 def: GenericDefId,
699 provided_count: u32,
700 expected_count: u32,
701 kind: IncorrectGenericsLenKind,
702 ) {
703 self.ctx.on_diagnostic(PathLoweringDiagnostic::IncorrectGenericsLen {
704 generics_source: self.generics_source,
705 provided_count,
706 expected_count,
707 kind,
708 def,
709 });
710 }
711
712 fn report_arg_mismatch(
713 &mut self,
714 param_id: GenericParamId,
715 arg_idx: u32,
716 has_self_arg: bool,
717 ) {
718 self.ctx.on_diagnostic(PathLoweringDiagnostic::IncorrectGenericsOrder {
719 generics_source: self.generics_source,
720 param_id,
721 arg_idx,
722 has_self_arg,
723 });
724 }
725
726 fn provided_kind(
727 &mut self,
728 param_id: GenericParamId,
729 param: GenericParamDataRef<'_>,
730 arg: &HirGenericArg,
731 ) -> GenericArg<'db> {
732 match (param, *arg) {
733 (
734 GenericParamDataRef::LifetimeParamData(_),
735 HirGenericArg::Lifetime(lifetime),
736 ) => self.ctx.ctx.lower_lifetime(lifetime).into(),
737 (GenericParamDataRef::TypeParamData(_), HirGenericArg::Type(type_ref)) => {
738 self.ctx.ctx.lower_ty(type_ref).into()
739 }
740 (GenericParamDataRef::ConstParamData(_), HirGenericArg::Const(konst)) => {
741 let GenericParamId::ConstParamId(const_id) = param_id else {
742 unreachable!("non-const param ID for const param");
743 };
744 self.ctx
745 .ctx
746 .lower_const(konst, const_param_ty(self.ctx.ctx.db, const_id), false)
747 .into()
748 }
749 _ => unreachable!("unmatching param kinds were passed to `provided_kind()`"),
750 }
751 }
752
753 fn provided_type_like_const(
754 &mut self,
755 type_ref: TypeRefId,
756 const_ty: Ty<'db>,
757 arg: TypeLikeConst<'_>,
758 ) -> Const<'db> {
759 match arg {
760 TypeLikeConst::Path(path) => self.ctx.ctx.lower_path_as_const(path, const_ty),
761 TypeLikeConst::Infer => self.ctx.ctx.next_const_var(type_ref.into()),
762 }
763 }
764
765 fn inferred_kind(
766 &mut self,
767 def: GenericDefId,
768 param_id: GenericParamId,
769 param: GenericParamDataRef<'_>,
770 infer_args: bool,
771 preceding_args: &[GenericArg<'db>],
772 had_count_error: bool,
773 ) -> GenericArg<'db> {
774 let default = || {
775 self.ctx.ctx.db.generic_defaults(def).get(preceding_args.len()).map(|default| {
776 default.instantiate(self.ctx.ctx.interner, preceding_args).skip_norm_wip()
777 })
778 };
779 let span = if !infer_args || had_count_error { Span::Dummy } else { self.span };
781 match param {
782 GenericParamDataRef::LifetimeParamData(_) => {
783 self.ctx.ctx.next_region_var(span).into()
784 }
785 GenericParamDataRef::TypeParamData(param) => {
786 if !infer_args
787 && param.default.is_some()
788 && let Some(default) = default()
789 {
790 return default;
791 }
792 self.ctx.ctx.next_ty_var(span).into()
793 }
794 GenericParamDataRef::ConstParamData(param) => {
795 if !infer_args
796 && param.default.is_some()
797 && let Some(default) = default()
798 {
799 return default;
800 }
801 let GenericParamId::ConstParamId(_) = param_id else {
802 unreachable!("non-const param ID for const param");
803 };
804 self.ctx.ctx.next_const_var(span).into()
805 }
806 }
807 }
808
809 fn parent_arg(&mut self, _param_idx: u32, param_id: GenericParamId) -> GenericArg<'db> {
810 match param_id {
811 GenericParamId::TypeParamId(_) => {
812 Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into()
813 }
814 GenericParamId::ConstParamId(_) => self.ctx.ctx.types.consts.error.into(),
815 GenericParamId::LifetimeParamId(_) => self.ctx.ctx.types.regions.error.into(),
816 }
817 }
818
819 fn report_elided_lifetimes_in_path(
820 &mut self,
821 def: GenericDefId,
822 expected_count: u32,
823 hard_error: bool,
824 ) {
825 self.ctx.on_diagnostic(PathLoweringDiagnostic::ElidedLifetimesInPath {
826 generics_source: self.generics_source,
827 def,
828 expected_count,
829 hard_error,
830 });
831 }
832
833 fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32) {
834 self.ctx.on_diagnostic(PathLoweringDiagnostic::ElisionFailure {
835 generics_source: self.generics_source,
836 def,
837 expected_count,
838 });
839 }
840
841 fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32) {
842 self.ctx.on_diagnostic(PathLoweringDiagnostic::MissingLifetime {
843 generics_source: self.generics_source,
844 def,
845 expected_count,
846 });
847 }
848 }
849
850 substs_from_args_and_bindings(
851 self.ctx.db,
852 self.ctx.store,
853 args_and_bindings,
854 def,
855 infer_args,
856 lifetime_elision,
857 lowering_assoc_type_generics,
858 explicit_self_ty,
859 &mut LowererCtx { ctx: self, generics_source, span },
860 )
861 }
862
863 pub(crate) fn lower_trait_ref_from_resolved_path(
864 &mut self,
865 resolved: TraitId,
866 explicit_self_ty: Ty<'db>,
867 infer_args: bool,
868 span: Span,
869 ) -> TraitRef<'db> {
870 let args = self.trait_ref_substs_from_path(resolved, explicit_self_ty, infer_args, span);
871 TraitRef::new_from_args(self.ctx.interner, resolved.into(), args)
872 }
873
874 fn trait_ref_substs_from_path(
875 &mut self,
876 resolved: TraitId,
877 explicit_self_ty: Ty<'db>,
878 infer_args: bool,
879 span: Span,
880 ) -> GenericArgs<'db> {
881 self.substs_from_path_segment(
882 resolved.into(),
883 infer_args,
884 Some(explicit_self_ty),
885 false,
886 span,
887 )
888 }
889
890 pub(super) fn assoc_type_bindings_from_type_bound(
891 mut self,
892 trait_ref: TraitRef<'db>,
893 span: Span,
894 ) -> Option<impl Iterator<Item = (Clause<'db>, GenericPredicateSource)> + use<'a, 'b, 'db>>
895 {
896 let interner = self.ctx.interner;
897 self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| {
898 args_and_bindings.bindings.iter().enumerate().flat_map(move |(binding_idx, binding)| {
899 let found = associated_type_by_name_including_super_traits_allow_ambiguity(
900 self.ctx.db,
901 trait_ref,
902 binding.name.clone(),
903 );
904 let (associated_ty, super_trait_args) = match found {
905 None => return SmallVec::new(),
906 Some(t) => t,
907 };
908 let args =
909 self.with_lifetime_elision(LifetimeElisionKind::AnonymousReportError, |this| {
910 this.substs_from_args_and_bindings(
915 binding.args.as_ref(),
916 associated_ty.into(),
917 false, Some(super_trait_args.type_at(0)),
919 PathGenericsSource::AssocType {
920 segment: this.current_segment_u32(),
921 assoc_type: binding_idx as u32,
922 },
923 false,
924 this.ctx.lifetime_elision,
925 span,
926 )
927 });
928 let args = GenericArgs::new_from_iter(
929 super_trait_args.iter().chain(args.iter().skip(super_trait_args.len())),
930 );
931 let projection_term = AliasTerm::new_from_args(
932 interner,
933 AliasTermKind::ProjectionTy { def_id: associated_ty.into() },
934 args,
935 );
936 let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity(
937 binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
938 );
939 if let Some(type_ref) = binding.type_ref {
940 let lifetime_elision =
941 if args_and_bindings.parenthesized == GenericArgsParentheses::ParenSugar {
942 LifetimeElisionKind::for_fn_ret(self.ctx.interner)
944 } else {
945 self.ctx.lifetime_elision
946 };
947 self.with_lifetime_elision(lifetime_elision, |this| {
948 match (&this.ctx.store[type_ref], this.ctx.impl_trait_mode.mode) {
949 (TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (),
950 (
951 _,
952 ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque,
953 ) => {
954 let ty = this.ctx.lower_ty(type_ref);
955 let bound_vars = this.ctx.peek_bound_vars();
956 let pred = Clause(Predicate::new(
957 interner,
958 Binder::bind_with_vars(
959 rustc_type_ir::PredicateKind::Clause(
960 rustc_type_ir::ClauseKind::Projection(
961 ProjectionPredicate {
962 projection_term,
963 term: ty.into(),
964 },
965 ),
966 ),
967 bound_vars,
968 ),
969 ));
970 predicates.push((pred, GenericPredicateSource::SelfOnly));
971 }
972 }
973 })
974 }
975 for bound in binding.bounds.iter() {
976 predicates.extend(
977 self.ctx
978 .lower_type_bound(
979 bound,
980 Ty::new_alias(
981 self.ctx.interner,
982 AliasTy::new_from_args(
983 self.ctx.interner,
984 AliasTyKind::Projection { def_id: associated_ty.into() },
985 args,
986 ),
987 ),
988 false,
989 )
990 .map(|(pred, _)| (pred, GenericPredicateSource::AssocTyBound)),
991 );
992 }
993 predicates
994 })
995 })
996 }
997
998 pub(crate) fn interner(&self) -> DbInterner<'db> {
999 self.ctx.interner
1000 }
1001}
1002
1003pub(crate) enum TypeLikeConst<'a> {
1005 Infer,
1006 Path(&'a Path),
1007}
1008
1009pub(crate) trait GenericArgsLowerer<'db> {
1010 fn report_elided_lifetimes_in_path(
1011 &mut self,
1012 def: GenericDefId,
1013 expected_count: u32,
1014 hard_error: bool,
1015 );
1016
1017 fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32);
1018
1019 fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32);
1020
1021 fn report_len_mismatch(
1022 &mut self,
1023 def: GenericDefId,
1024 provided_count: u32,
1025 expected_count: u32,
1026 kind: IncorrectGenericsLenKind,
1027 );
1028
1029 fn report_arg_mismatch(&mut self, param_id: GenericParamId, arg_idx: u32, has_self_arg: bool);
1030
1031 fn provided_kind(
1032 &mut self,
1033 param_id: GenericParamId,
1034 param: GenericParamDataRef<'_>,
1035 arg: &HirGenericArg,
1036 ) -> GenericArg<'db>;
1037
1038 fn provided_type_like_const(
1039 &mut self,
1040 type_ref: TypeRefId,
1041 const_ty: Ty<'db>,
1042 arg: TypeLikeConst<'_>,
1043 ) -> Const<'db>;
1044
1045 fn inferred_kind(
1046 &mut self,
1047 def: GenericDefId,
1048 param_id: GenericParamId,
1049 param: GenericParamDataRef<'_>,
1050 infer_args: bool,
1051 preceding_args: &[GenericArg<'db>],
1052 had_count_error: bool,
1053 ) -> GenericArg<'db>;
1054
1055 fn parent_arg(&mut self, param_idx: u32, param_id: GenericParamId) -> GenericArg<'db>;
1056}
1057
1058fn check_generic_args_len<'db>(
1060 args_and_bindings: Option<&HirGenericArgs>,
1061 def: GenericDefId,
1062 def_generics: &Generics<'db>,
1063 infer_args: bool,
1064 lifetime_elision: &LifetimeElisionKind<'db>,
1065 lowering_assoc_type_generics: bool,
1066 ctx: &mut impl GenericArgsLowerer<'db>,
1067) -> bool {
1068 let mut had_error = false;
1069
1070 let (mut provided_lifetimes_count, mut provided_types_and_consts_count) = (0usize, 0usize);
1071 if let Some(args_and_bindings) = args_and_bindings {
1072 let args_no_self = &args_and_bindings.args[usize::from(args_and_bindings.has_self_type)..];
1073 for arg in args_no_self {
1074 match arg {
1075 HirGenericArg::Lifetime(_) => provided_lifetimes_count += 1,
1076 HirGenericArg::Type(_) | HirGenericArg::Const(_) => {
1077 provided_types_and_consts_count += 1
1078 }
1079 }
1080 }
1081 }
1082
1083 let lifetime_args_len = def_generics.len_lifetimes_self();
1084 if provided_lifetimes_count == 0
1085 && lifetime_args_len > 0
1086 && (!lowering_assoc_type_generics || infer_args)
1087 {
1088 match lifetime_elision {
1091 &LifetimeElisionKind::AnonymousCreateParameter { report_in_path } => {
1092 ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, report_in_path);
1093 had_error |= report_in_path;
1094 }
1095 LifetimeElisionKind::AnonymousReportError => {
1096 ctx.report_missing_lifetime(def, lifetime_args_len as u32);
1097 had_error = true
1098 }
1099 LifetimeElisionKind::ElisionFailure => {
1100 ctx.report_elision_failure(def, lifetime_args_len as u32);
1101 had_error = true;
1102 }
1103 LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
1104 }
1106 LifetimeElisionKind::Elided(_) => {
1107 ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, false);
1108 }
1109 LifetimeElisionKind::Infer => {
1110 }
1112 }
1113 } else if lifetime_args_len != provided_lifetimes_count {
1114 ctx.report_len_mismatch(
1115 def,
1116 provided_lifetimes_count as u32,
1117 lifetime_args_len as u32,
1118 IncorrectGenericsLenKind::Lifetimes,
1119 );
1120 had_error = true;
1121 }
1122
1123 let defaults_count =
1124 def_generics.iter_self_type_or_consts().filter(|(_, param)| param.has_default()).count();
1125 let named_type_and_const_params_count = def_generics
1126 .iter_self_type_or_consts()
1127 .filter(|(_, param)| match param {
1128 TypeOrConstParamData::TypeParamData(param) => {
1129 param.provenance == TypeParamProvenance::TypeParamList
1130 }
1131 TypeOrConstParamData::ConstParamData(_) => true,
1132 })
1133 .count();
1134 let expected_max = named_type_and_const_params_count;
1135 let expected_min =
1136 if infer_args { 0 } else { named_type_and_const_params_count - defaults_count };
1137 if provided_types_and_consts_count < expected_min
1138 || expected_max < provided_types_and_consts_count
1139 {
1140 ctx.report_len_mismatch(
1141 def,
1142 provided_types_and_consts_count as u32,
1143 named_type_and_const_params_count as u32,
1144 IncorrectGenericsLenKind::TypesAndConsts,
1145 );
1146 had_error = true;
1147 }
1148
1149 had_error
1150}
1151
1152pub(crate) fn substs_from_args_and_bindings<'db>(
1153 db: &'db dyn HirDatabase,
1154 store: &ExpressionStore,
1155 args_and_bindings: Option<&HirGenericArgs>,
1156 def: GenericDefId,
1157 mut infer_args: bool,
1158 lifetime_elision: LifetimeElisionKind<'db>,
1159 lowering_assoc_type_generics: bool,
1160 explicit_self_ty: Option<Ty<'db>>,
1161 ctx: &mut impl GenericArgsLowerer<'db>,
1162) -> GenericArgs<'db> {
1163 let interner = DbInterner::new_no_crate(db);
1164
1165 tracing::debug!(?args_and_bindings);
1166
1167 let def_generics = generics(db, def);
1173 let args_slice = args_and_bindings.map(|it| &*it.args).unwrap_or_default();
1174
1175 let has_non_lifetime_args =
1177 args_slice.iter().any(|arg| !matches!(arg, HirGenericArg::Lifetime(_)));
1178 infer_args &= !has_non_lifetime_args;
1179
1180 let had_count_error = check_generic_args_len(
1181 args_and_bindings,
1182 def,
1183 &def_generics,
1184 infer_args,
1185 &lifetime_elision,
1186 lowering_assoc_type_generics,
1187 ctx,
1188 );
1189
1190 let mut substs = Vec::with_capacity(def_generics.len(true));
1191
1192 substs.extend(
1193 def_generics.iter_parent_id().enumerate().map(|(idx, id)| ctx.parent_arg(idx as u32, id)),
1194 );
1195
1196 let mut args = args_slice.iter().enumerate().peekable();
1197 let mut params = def_generics.iter_self().peekable();
1198
1199 let mut force_infer_lt = None;
1204
1205 let has_self_arg = args_and_bindings.is_some_and(|it| it.has_self_type);
1206 if let Some(&(
1209 self_param_id,
1210 self_param @ GenericParamDataRef::TypeParamData(TypeParamData {
1211 provenance: TypeParamProvenance::TraitSelf,
1212 ..
1213 }),
1214 )) = params.peek()
1215 {
1216 let self_ty = if has_self_arg {
1217 let (_, self_ty) = args.next().expect("has_self_type=true, should have Self type");
1218 ctx.provided_kind(self_param_id, self_param, self_ty)
1219 } else {
1220 explicit_self_ty.map(|it| it.into()).unwrap_or_else(|| {
1221 ctx.inferred_kind(
1222 def,
1223 self_param_id,
1224 self_param,
1225 infer_args,
1226 &substs,
1227 had_count_error,
1228 )
1229 })
1230 };
1231 params.next();
1232 substs.push(self_ty);
1233 } else if has_self_arg {
1234 args.next();
1239 }
1240
1241 loop {
1242 match (args.peek(), params.peek()) {
1247 (Some(&(arg_idx, arg)), Some(&(param_id, param))) => match (arg, param) {
1248 (HirGenericArg::Type(_), GenericParamDataRef::TypeParamData(type_param))
1249 if type_param.provenance == TypeParamProvenance::ArgumentImplTrait =>
1250 {
1251 substs.push(ctx.inferred_kind(
1254 def,
1255 param_id,
1256 param,
1257 infer_args,
1258 &substs,
1259 had_count_error,
1260 ));
1261 params.next();
1262 }
1263 (HirGenericArg::Lifetime(_), GenericParamDataRef::LifetimeParamData(_))
1264 | (HirGenericArg::Type(_), GenericParamDataRef::TypeParamData(_))
1265 | (HirGenericArg::Const(_), GenericParamDataRef::ConstParamData(_)) => {
1266 substs.push(ctx.provided_kind(param_id, param, arg));
1267 args.next();
1268 params.next();
1269 }
1270 (
1271 HirGenericArg::Type(_) | HirGenericArg::Const(_),
1272 GenericParamDataRef::LifetimeParamData(_),
1273 ) => {
1274 substs.push(ctx.inferred_kind(
1277 def,
1278 param_id,
1279 param,
1280 infer_args,
1281 &substs,
1282 had_count_error,
1283 ));
1284 params.next();
1285 force_infer_lt = Some((arg_idx as u32, param_id));
1286 }
1287 (HirGenericArg::Type(type_ref), GenericParamDataRef::ConstParamData(_)) => {
1288 if let Some(konst) = type_looks_like_const(store, *type_ref) {
1289 let GenericParamId::ConstParamId(param_id) = param_id else {
1290 panic!("unmatching param kinds");
1291 };
1292 let const_ty = const_param_ty(db, param_id);
1293 substs
1294 .push(ctx.provided_type_like_const(*type_ref, const_ty, konst).into());
1295 args.next();
1296 params.next();
1297 } else {
1298 if !had_count_error {
1300 ctx.report_arg_mismatch(param_id, arg_idx as u32, has_self_arg);
1301 }
1302 while args.next().is_some() {}
1303 }
1304 }
1305 _ => {
1306 if !had_count_error {
1311 ctx.report_arg_mismatch(param_id, arg_idx as u32, has_self_arg);
1312 }
1313
1314 while args.next().is_some() {}
1320 }
1321 },
1322
1323 (Some(&(_, arg)), None) => {
1324 if !had_count_error {
1332 assert!(
1333 matches!(arg, HirGenericArg::Lifetime(_)),
1334 "the only possible situation here is incorrect lifetime order"
1335 );
1336 let (provided_arg_idx, param_id) =
1337 force_infer_lt.expect("lifetimes ought to have been inferred");
1338 ctx.report_arg_mismatch(param_id, provided_arg_idx, has_self_arg);
1339 }
1340
1341 break;
1342 }
1343
1344 (None, Some(&(param_id, param))) => {
1345 let param = if let GenericParamId::LifetimeParamId(_) = param_id {
1347 match &lifetime_elision {
1348 LifetimeElisionKind::ElisionFailure
1349 | LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }
1350 | LifetimeElisionKind::AnonymousReportError => {
1351 assert!(had_count_error);
1352 ctx.inferred_kind(
1353 def,
1354 param_id,
1355 param,
1356 infer_args,
1357 &substs,
1358 had_count_error,
1359 )
1360 }
1361 LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
1362 Region::new_static(interner).into()
1363 }
1364 LifetimeElisionKind::Elided(lifetime) => (*lifetime).into(),
1365 LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }
1366 | LifetimeElisionKind::Infer => {
1367 ctx.inferred_kind(
1370 def,
1371 param_id,
1372 param,
1373 infer_args,
1374 &substs,
1375 had_count_error,
1376 )
1377 }
1378 }
1379 } else {
1380 ctx.inferred_kind(def, param_id, param, infer_args, &substs, had_count_error)
1381 };
1382 substs.push(param);
1383 params.next();
1384 }
1385
1386 (None, None) => break,
1387 }
1388 }
1389
1390 GenericArgs::new_from_slice(&substs)
1391}
1392
1393fn type_looks_like_const(
1394 store: &ExpressionStore,
1395 type_ref: TypeRefId,
1396) -> Option<TypeLikeConst<'_>> {
1397 let type_ref = &store[type_ref];
1403 match type_ref {
1404 TypeRef::Path(path) => Some(TypeLikeConst::Path(path)),
1405 TypeRef::Placeholder => Some(TypeLikeConst::Infer),
1406 _ => None,
1407 }
1408}