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 self.on_diagnostic(PathLoweringDiagnostic::UnresolvedAssociatedType {
503 segment: self.current_segment_u32(),
504 });
505 return self.ctx.types.types.error;
506 };
507 assoc_type
508 .get_with(|(assoc_type, trait_args)| (*assoc_type, trait_args.as_ref()))
509 .skip_binder()
510 }
511 Some(TypeNs::SelfType(impl_)) => {
512 let Some(impl_trait) = db.impl_trait(impl_) else {
513 return self.ctx.types.types.error;
514 };
515 let impl_trait = impl_trait.instantiate_identity().skip_norm_wip();
516 let AssocTypeShorthandResolution::Resolved(assoc_type) =
518 super::resolve_type_param_assoc_type_shorthand(
519 db,
520 impl_trait.def_id.0.into(),
521 TypeParamId::trait_self(impl_trait.def_id.0),
522 assoc_name.clone(),
523 )
524 else {
525 self.on_diagnostic(PathLoweringDiagnostic::UnresolvedAssociatedType {
526 segment: self.current_segment_u32(),
527 });
528 return self.ctx.types.types.error;
529 };
530 let (assoc_type, trait_args) = assoc_type
531 .get_with(|(assoc_type, trait_args)| (*assoc_type, trait_args.as_ref()))
532 .skip_binder();
533 (
534 assoc_type,
535 EarlyBinder::bind(trait_args)
536 .instantiate(interner, impl_trait.args)
537 .skip_norm_wip(),
538 )
539 }
540 _ => return self.ctx.types.types.error,
541 };
542
543 let substs = self.substs_from_path_segment(assoc_type.into(), infer_args, None, true, span);
548
549 let substs = GenericArgs::new_from_iter(
550 trait_args.iter().chain(substs.iter().skip(trait_args.len())),
551 );
552
553 Ty::new_projection_from_args(interner, assoc_type.into(), substs)
554 }
555
556 fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool, span: Span) -> Ty<'db> {
557 let generic_def = match typeable {
558 TyDefId::BuiltinType(builtinty) => {
559 return Ty::from_builtin_type(self.ctx.interner, builtinty);
560 }
561 TyDefId::AdtId(it) => it.into(),
562 TyDefId::TypeAliasId(it) => it.into(),
563 };
564 let args = self.substs_from_path_segment(generic_def, infer_args, None, false, span);
565 let ty = ty_query(self.ctx.db, typeable);
566 ty.instantiate(self.ctx.interner, args).skip_norm_wip()
567 }
568
569 pub(crate) fn substs_from_path(
572 &mut self,
573 resolved: ValueTyDefId,
577 infer_args: bool,
578 lowering_assoc_type_generics: bool,
579 span: Span,
580 ) -> GenericArgs<'db> {
581 let prev_current_segment_idx = self.current_segment_idx;
582 let prev_current_segment = self.current_or_prev_segment;
583
584 let generic_def = match resolved {
585 ValueTyDefId::FunctionId(it) => it.into(),
586 ValueTyDefId::StructId(it) => it.into(),
587 ValueTyDefId::UnionId(it) => it.into(),
588 ValueTyDefId::ConstId(it) => it.into(),
589 ValueTyDefId::StaticId(_) => {
590 return GenericArgs::empty();
591 }
592 ValueTyDefId::EnumVariantId(var) => {
593 let penultimate_idx = self.current_segment_idx.wrapping_sub(1);
606 let penultimate = self.segments.get(penultimate_idx);
607 if let Some(penultimate) = penultimate
608 && self.current_or_prev_segment.args_and_bindings.is_none()
609 && penultimate.args_and_bindings.is_some()
610 {
611 self.current_segment_idx = penultimate_idx;
612 self.current_or_prev_segment = penultimate;
613 }
614 var.lookup(self.ctx.db).parent.into()
615 }
616 };
617 let result = self.substs_from_path_segment(
618 generic_def,
619 infer_args,
620 None,
621 lowering_assoc_type_generics,
622 span,
623 );
624 self.current_segment_idx = prev_current_segment_idx;
625 self.current_or_prev_segment = prev_current_segment;
626 result
627 }
628
629 pub(crate) fn substs_from_path_segment(
630 &mut self,
631 def: GenericDefId,
632 infer_args: bool,
633 explicit_self_ty: Option<Ty<'db>>,
634 lowering_assoc_type_generics: bool,
635 span: Span,
636 ) -> GenericArgs<'db> {
637 let old_lifetime_elision = self.ctx.lifetime_elision;
638
639 if let Some(args) = self.current_or_prev_segment.args_and_bindings
640 && args.parenthesized != GenericArgsParentheses::No
641 {
642 let prohibit_parens = match def {
643 GenericDefId::TraitId(trait_) => {
644 let is_rtn = args.parenthesized == GenericArgsParentheses::ReturnTypeNotation;
646 let is_fn_trait = TraitSignature::of(self.ctx.db, trait_)
647 .flags
648 .contains(TraitFlags::RUSTC_PAREN_SUGAR);
649 is_rtn || !is_fn_trait
650 }
651 _ => true,
652 };
653
654 if prohibit_parens {
655 let segment = self.current_segment_u32();
656 self.on_diagnostic(
657 PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
658 );
659
660 return GenericArgs::error_for_item(self.ctx.interner, def.into());
661 }
662
663 self.ctx.lifetime_elision =
665 LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false };
666 }
667
668 let result = self.substs_from_args_and_bindings(
669 self.current_or_prev_segment.args_and_bindings,
670 def,
671 infer_args,
672 explicit_self_ty,
673 PathGenericsSource::Segment(self.current_segment_u32()),
674 lowering_assoc_type_generics,
675 self.ctx.lifetime_elision,
676 span,
677 );
678 self.ctx.lifetime_elision = old_lifetime_elision;
679 result
680 }
681
682 pub(super) fn substs_from_args_and_bindings(
683 &mut self,
684 args_and_bindings: Option<&HirGenericArgs>,
685 def: GenericDefId,
686 infer_args: bool,
687 explicit_self_ty: Option<Ty<'db>>,
688 generics_source: PathGenericsSource,
689 lowering_assoc_type_generics: bool,
690 lifetime_elision: LifetimeElisionKind<'db>,
691 span: Span,
692 ) -> GenericArgs<'db> {
693 struct LowererCtx<'a, 'b, 'c, 'db> {
694 ctx: &'a mut PathLoweringContext<'b, 'c, 'db>,
695 generics_source: PathGenericsSource,
696 span: Span,
697 }
698
699 impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, '_, '_, 'db> {
700 fn report_len_mismatch(
701 &mut self,
702 def: GenericDefId,
703 provided_count: u32,
704 expected_count: u32,
705 kind: IncorrectGenericsLenKind,
706 ) {
707 self.ctx.on_diagnostic(PathLoweringDiagnostic::IncorrectGenericsLen {
708 generics_source: self.generics_source,
709 provided_count,
710 expected_count,
711 kind,
712 def,
713 });
714 }
715
716 fn report_arg_mismatch(
717 &mut self,
718 param_id: GenericParamId,
719 arg_idx: u32,
720 has_self_arg: bool,
721 ) {
722 self.ctx.on_diagnostic(PathLoweringDiagnostic::IncorrectGenericsOrder {
723 generics_source: self.generics_source,
724 param_id,
725 arg_idx,
726 has_self_arg,
727 });
728 }
729
730 fn provided_kind(
731 &mut self,
732 param_id: GenericParamId,
733 param: GenericParamDataRef<'_>,
734 arg: &HirGenericArg,
735 ) -> GenericArg<'db> {
736 match (param, *arg) {
737 (
738 GenericParamDataRef::LifetimeParamData(_),
739 HirGenericArg::Lifetime(lifetime),
740 ) => self.ctx.ctx.lower_lifetime(lifetime).into(),
741 (GenericParamDataRef::TypeParamData(_), HirGenericArg::Type(type_ref)) => {
742 self.ctx.ctx.lower_ty(type_ref).into()
743 }
744 (GenericParamDataRef::ConstParamData(_), HirGenericArg::Const(konst)) => {
745 let GenericParamId::ConstParamId(const_id) = param_id else {
746 unreachable!("non-const param ID for const param");
747 };
748 self.ctx
749 .ctx
750 .lower_const(konst, const_param_ty(self.ctx.ctx.db, const_id), false)
751 .into()
752 }
753 _ => unreachable!("unmatching param kinds were passed to `provided_kind()`"),
754 }
755 }
756
757 fn provided_type_like_const(
758 &mut self,
759 type_ref: TypeRefId,
760 const_ty: Ty<'db>,
761 arg: TypeLikeConst<'_>,
762 ) -> Const<'db> {
763 match arg {
764 TypeLikeConst::Path(path) => self.ctx.ctx.lower_path_as_const(path, const_ty),
765 TypeLikeConst::Infer => self.ctx.ctx.next_const_var(type_ref.into()),
766 }
767 }
768
769 fn inferred_kind(
770 &mut self,
771 def: GenericDefId,
772 param_id: GenericParamId,
773 param: GenericParamDataRef<'_>,
774 infer_args: bool,
775 preceding_args: &[GenericArg<'db>],
776 had_count_error: bool,
777 ) -> GenericArg<'db> {
778 let default = || {
779 self.ctx.ctx.db.generic_defaults(def).get(preceding_args.len()).map(|default| {
780 default.instantiate(self.ctx.ctx.interner, preceding_args).skip_norm_wip()
781 })
782 };
783 let span = if !infer_args || had_count_error { Span::Dummy } else { self.span };
785 match param {
786 GenericParamDataRef::LifetimeParamData(_) => {
787 self.ctx.ctx.next_region_var(span).into()
788 }
789 GenericParamDataRef::TypeParamData(param) => {
790 if !infer_args
791 && param.default.is_some()
792 && let Some(default) = default()
793 {
794 return default;
795 }
796 self.ctx.ctx.next_ty_var(span).into()
797 }
798 GenericParamDataRef::ConstParamData(param) => {
799 if !infer_args
800 && param.default.is_some()
801 && let Some(default) = default()
802 {
803 return default;
804 }
805 let GenericParamId::ConstParamId(_) = param_id else {
806 unreachable!("non-const param ID for const param");
807 };
808 self.ctx.ctx.next_const_var(span).into()
809 }
810 }
811 }
812
813 fn parent_arg(&mut self, _param_idx: u32, param_id: GenericParamId) -> GenericArg<'db> {
814 match param_id {
815 GenericParamId::TypeParamId(_) => {
816 Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into()
817 }
818 GenericParamId::ConstParamId(_) => self.ctx.ctx.types.consts.error.into(),
819 GenericParamId::LifetimeParamId(_) => self.ctx.ctx.types.regions.error.into(),
820 }
821 }
822
823 fn report_elided_lifetimes_in_path(
824 &mut self,
825 def: GenericDefId,
826 expected_count: u32,
827 hard_error: bool,
828 ) {
829 self.ctx.on_diagnostic(PathLoweringDiagnostic::ElidedLifetimesInPath {
830 generics_source: self.generics_source,
831 def,
832 expected_count,
833 hard_error,
834 });
835 }
836
837 fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32) {
838 self.ctx.on_diagnostic(PathLoweringDiagnostic::ElisionFailure {
839 generics_source: self.generics_source,
840 def,
841 expected_count,
842 });
843 }
844
845 fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32) {
846 self.ctx.on_diagnostic(PathLoweringDiagnostic::MissingLifetime {
847 generics_source: self.generics_source,
848 def,
849 expected_count,
850 });
851 }
852 }
853
854 substs_from_args_and_bindings(
855 self.ctx.db,
856 self.ctx.store,
857 args_and_bindings,
858 def,
859 infer_args,
860 lifetime_elision,
861 lowering_assoc_type_generics,
862 explicit_self_ty,
863 &mut LowererCtx { ctx: self, generics_source, span },
864 )
865 }
866
867 pub(crate) fn lower_trait_ref_from_resolved_path(
868 &mut self,
869 resolved: TraitId,
870 explicit_self_ty: Ty<'db>,
871 infer_args: bool,
872 span: Span,
873 ) -> TraitRef<'db> {
874 let args = self.trait_ref_substs_from_path(resolved, explicit_self_ty, infer_args, span);
875 TraitRef::new_from_args(self.ctx.interner, resolved.into(), args)
876 }
877
878 fn trait_ref_substs_from_path(
879 &mut self,
880 resolved: TraitId,
881 explicit_self_ty: Ty<'db>,
882 infer_args: bool,
883 span: Span,
884 ) -> GenericArgs<'db> {
885 self.substs_from_path_segment(
886 resolved.into(),
887 infer_args,
888 Some(explicit_self_ty),
889 false,
890 span,
891 )
892 }
893
894 pub(super) fn assoc_type_bindings_from_type_bound(
895 mut self,
896 trait_ref: TraitRef<'db>,
897 span: Span,
898 ) -> Option<impl Iterator<Item = (Clause<'db>, GenericPredicateSource)> + use<'a, 'b, 'db>>
899 {
900 let interner = self.ctx.interner;
901 self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| {
902 args_and_bindings.bindings.iter().enumerate().flat_map(move |(binding_idx, binding)| {
903 let found = associated_type_by_name_including_super_traits_allow_ambiguity(
904 self.ctx.db,
905 trait_ref,
906 binding.name.clone(),
907 );
908 let (associated_ty, super_trait_args) = match found {
909 None => return SmallVec::new(),
910 Some(t) => t,
911 };
912 let args =
913 self.with_lifetime_elision(LifetimeElisionKind::AnonymousReportError, |this| {
914 this.substs_from_args_and_bindings(
919 binding.args.as_ref(),
920 associated_ty.into(),
921 false, Some(super_trait_args.type_at(0)),
923 PathGenericsSource::AssocType {
924 segment: this.current_segment_u32(),
925 assoc_type: binding_idx as u32,
926 },
927 false,
928 this.ctx.lifetime_elision,
929 span,
930 )
931 });
932 let args = GenericArgs::new_from_iter(
933 super_trait_args.iter().chain(args.iter().skip(super_trait_args.len())),
934 );
935 let projection_term = AliasTerm::new_from_args(
936 interner,
937 AliasTermKind::ProjectionTy { def_id: associated_ty.into() },
938 args,
939 );
940 let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity(
941 binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
942 );
943 if let Some(type_ref) = binding.type_ref {
944 let lifetime_elision =
945 if args_and_bindings.parenthesized == GenericArgsParentheses::ParenSugar {
946 LifetimeElisionKind::for_fn_ret(self.ctx.interner)
948 } else {
949 self.ctx.lifetime_elision
950 };
951 self.with_lifetime_elision(lifetime_elision, |this| {
952 match (&this.ctx.store[type_ref], this.ctx.impl_trait_mode.mode) {
953 (TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (),
954 (
955 _,
956 ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque,
957 ) => {
958 let ty = this.ctx.lower_ty(type_ref);
959 let bound_vars = this.ctx.peek_bound_vars();
960 let pred = Clause(Predicate::new(
961 interner,
962 Binder::bind_with_vars(
963 rustc_type_ir::PredicateKind::Clause(
964 rustc_type_ir::ClauseKind::Projection(
965 ProjectionPredicate {
966 projection_term,
967 term: ty.into(),
968 },
969 ),
970 ),
971 bound_vars,
972 ),
973 ));
974 predicates.push((pred, GenericPredicateSource::SelfOnly));
975 }
976 }
977 })
978 }
979 for bound in binding.bounds.iter() {
980 predicates.extend(
981 self.ctx
982 .lower_type_bound(
983 bound,
984 Ty::new_alias(
985 self.ctx.interner,
986 AliasTy::new_from_args(
987 self.ctx.interner,
988 AliasTyKind::Projection { def_id: associated_ty.into() },
989 args,
990 ),
991 ),
992 false,
993 )
994 .map(|(pred, _)| (pred, GenericPredicateSource::AssocTyBound)),
995 );
996 }
997 predicates
998 })
999 })
1000 }
1001
1002 pub(crate) fn interner(&self) -> DbInterner<'db> {
1003 self.ctx.interner
1004 }
1005}
1006
1007pub(crate) enum TypeLikeConst<'a> {
1009 Infer,
1010 Path(&'a Path),
1011}
1012
1013pub(crate) trait GenericArgsLowerer<'db> {
1014 fn report_elided_lifetimes_in_path(
1015 &mut self,
1016 def: GenericDefId,
1017 expected_count: u32,
1018 hard_error: bool,
1019 );
1020
1021 fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32);
1022
1023 fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32);
1024
1025 fn report_len_mismatch(
1026 &mut self,
1027 def: GenericDefId,
1028 provided_count: u32,
1029 expected_count: u32,
1030 kind: IncorrectGenericsLenKind,
1031 );
1032
1033 fn report_arg_mismatch(&mut self, param_id: GenericParamId, arg_idx: u32, has_self_arg: bool);
1034
1035 fn provided_kind(
1036 &mut self,
1037 param_id: GenericParamId,
1038 param: GenericParamDataRef<'_>,
1039 arg: &HirGenericArg,
1040 ) -> GenericArg<'db>;
1041
1042 fn provided_type_like_const(
1043 &mut self,
1044 type_ref: TypeRefId,
1045 const_ty: Ty<'db>,
1046 arg: TypeLikeConst<'_>,
1047 ) -> Const<'db>;
1048
1049 fn inferred_kind(
1050 &mut self,
1051 def: GenericDefId,
1052 param_id: GenericParamId,
1053 param: GenericParamDataRef<'_>,
1054 infer_args: bool,
1055 preceding_args: &[GenericArg<'db>],
1056 had_count_error: bool,
1057 ) -> GenericArg<'db>;
1058
1059 fn parent_arg(&mut self, param_idx: u32, param_id: GenericParamId) -> GenericArg<'db>;
1060}
1061
1062fn check_generic_args_len<'db>(
1064 args_and_bindings: Option<&HirGenericArgs>,
1065 def: GenericDefId,
1066 def_generics: &Generics<'db>,
1067 infer_args: bool,
1068 lifetime_elision: &LifetimeElisionKind<'db>,
1069 lowering_assoc_type_generics: bool,
1070 ctx: &mut impl GenericArgsLowerer<'db>,
1071) -> bool {
1072 let mut had_error = false;
1073
1074 let (mut provided_lifetimes_count, mut provided_types_and_consts_count) = (0usize, 0usize);
1075 if let Some(args_and_bindings) = args_and_bindings {
1076 let args_no_self = &args_and_bindings.args[usize::from(args_and_bindings.has_self_type)..];
1077 for arg in args_no_self {
1078 match arg {
1079 HirGenericArg::Lifetime(_) => provided_lifetimes_count += 1,
1080 HirGenericArg::Type(_) | HirGenericArg::Const(_) => {
1081 provided_types_and_consts_count += 1
1082 }
1083 }
1084 }
1085 }
1086
1087 let lifetime_args_len = def_generics.len_lifetimes_self();
1088 if provided_lifetimes_count == 0
1089 && lifetime_args_len > 0
1090 && (!lowering_assoc_type_generics || infer_args)
1091 {
1092 match lifetime_elision {
1095 &LifetimeElisionKind::AnonymousCreateParameter { report_in_path } => {
1096 ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, report_in_path);
1097 had_error |= report_in_path;
1098 }
1099 LifetimeElisionKind::AnonymousReportError => {
1100 ctx.report_missing_lifetime(def, lifetime_args_len as u32);
1101 had_error = true
1102 }
1103 LifetimeElisionKind::ElisionFailure => {
1104 ctx.report_elision_failure(def, lifetime_args_len as u32);
1105 had_error = true;
1106 }
1107 LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
1108 }
1110 LifetimeElisionKind::Elided(_) => {
1111 ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, false);
1112 }
1113 LifetimeElisionKind::Infer => {
1114 }
1116 }
1117 } else if lifetime_args_len != provided_lifetimes_count {
1118 ctx.report_len_mismatch(
1119 def,
1120 provided_lifetimes_count as u32,
1121 lifetime_args_len as u32,
1122 IncorrectGenericsLenKind::Lifetimes,
1123 );
1124 had_error = true;
1125 }
1126
1127 let defaults_count =
1128 def_generics.iter_self_type_or_consts().filter(|(_, param)| param.has_default()).count();
1129 let named_type_and_const_params_count = def_generics
1130 .iter_self_type_or_consts()
1131 .filter(|(_, param)| match param {
1132 TypeOrConstParamData::TypeParamData(param) => {
1133 param.provenance == TypeParamProvenance::TypeParamList
1134 }
1135 TypeOrConstParamData::ConstParamData(_) => true,
1136 })
1137 .count();
1138 let expected_max = named_type_and_const_params_count;
1139 let expected_min =
1140 if infer_args { 0 } else { named_type_and_const_params_count - defaults_count };
1141 if provided_types_and_consts_count < expected_min
1142 || expected_max < provided_types_and_consts_count
1143 {
1144 ctx.report_len_mismatch(
1145 def,
1146 provided_types_and_consts_count as u32,
1147 named_type_and_const_params_count as u32,
1148 IncorrectGenericsLenKind::TypesAndConsts,
1149 );
1150 had_error = true;
1151 }
1152
1153 had_error
1154}
1155
1156pub(crate) fn substs_from_args_and_bindings<'db>(
1157 db: &'db dyn HirDatabase,
1158 store: &ExpressionStore,
1159 args_and_bindings: Option<&HirGenericArgs>,
1160 def: GenericDefId,
1161 mut infer_args: bool,
1162 lifetime_elision: LifetimeElisionKind<'db>,
1163 lowering_assoc_type_generics: bool,
1164 explicit_self_ty: Option<Ty<'db>>,
1165 ctx: &mut impl GenericArgsLowerer<'db>,
1166) -> GenericArgs<'db> {
1167 let interner = DbInterner::new_no_crate(db);
1168
1169 tracing::debug!(?args_and_bindings);
1170
1171 let def_generics = generics(db, def);
1177 let args_slice = args_and_bindings.map(|it| &*it.args).unwrap_or_default();
1178
1179 let has_non_lifetime_args =
1181 args_slice.iter().any(|arg| !matches!(arg, HirGenericArg::Lifetime(_)));
1182 infer_args &= !has_non_lifetime_args;
1183
1184 let had_count_error = check_generic_args_len(
1185 args_and_bindings,
1186 def,
1187 &def_generics,
1188 infer_args,
1189 &lifetime_elision,
1190 lowering_assoc_type_generics,
1191 ctx,
1192 );
1193
1194 let mut substs = Vec::with_capacity(def_generics.len(true));
1195
1196 substs.extend(
1197 def_generics.iter_parent_id().enumerate().map(|(idx, id)| ctx.parent_arg(idx as u32, id)),
1198 );
1199
1200 let mut args = args_slice.iter().enumerate().peekable();
1201 let mut params = def_generics.iter_self().peekable();
1202
1203 let mut force_infer_lt = None;
1208
1209 let has_self_arg = args_and_bindings.is_some_and(|it| it.has_self_type);
1210 if let Some(&(
1213 self_param_id,
1214 self_param @ GenericParamDataRef::TypeParamData(TypeParamData {
1215 provenance: TypeParamProvenance::TraitSelf,
1216 ..
1217 }),
1218 )) = params.peek()
1219 {
1220 let self_ty = if has_self_arg {
1221 let (_, self_ty) = args.next().expect("has_self_type=true, should have Self type");
1222 ctx.provided_kind(self_param_id, self_param, self_ty)
1223 } else {
1224 explicit_self_ty.map(|it| it.into()).unwrap_or_else(|| {
1225 ctx.inferred_kind(
1226 def,
1227 self_param_id,
1228 self_param,
1229 infer_args,
1230 &substs,
1231 had_count_error,
1232 )
1233 })
1234 };
1235 params.next();
1236 substs.push(self_ty);
1237 } else if has_self_arg {
1238 args.next();
1243 }
1244
1245 loop {
1246 match (args.peek(), params.peek()) {
1251 (Some(&(arg_idx, arg)), Some(&(param_id, param))) => match (arg, param) {
1252 (HirGenericArg::Type(_), GenericParamDataRef::TypeParamData(type_param))
1253 if type_param.provenance == TypeParamProvenance::ArgumentImplTrait =>
1254 {
1255 substs.push(ctx.inferred_kind(
1258 def,
1259 param_id,
1260 param,
1261 infer_args,
1262 &substs,
1263 had_count_error,
1264 ));
1265 params.next();
1266 }
1267 (HirGenericArg::Lifetime(_), GenericParamDataRef::LifetimeParamData(_))
1268 | (HirGenericArg::Type(_), GenericParamDataRef::TypeParamData(_))
1269 | (HirGenericArg::Const(_), GenericParamDataRef::ConstParamData(_)) => {
1270 substs.push(ctx.provided_kind(param_id, param, arg));
1271 args.next();
1272 params.next();
1273 }
1274 (
1275 HirGenericArg::Type(_) | HirGenericArg::Const(_),
1276 GenericParamDataRef::LifetimeParamData(_),
1277 ) => {
1278 substs.push(ctx.inferred_kind(
1281 def,
1282 param_id,
1283 param,
1284 infer_args,
1285 &substs,
1286 had_count_error,
1287 ));
1288 params.next();
1289 force_infer_lt = Some((arg_idx as u32, param_id));
1290 }
1291 (HirGenericArg::Type(type_ref), GenericParamDataRef::ConstParamData(_)) => {
1292 if let Some(konst) = type_looks_like_const(store, *type_ref) {
1293 let GenericParamId::ConstParamId(param_id) = param_id else {
1294 panic!("unmatching param kinds");
1295 };
1296 let const_ty = const_param_ty(db, param_id);
1297 substs
1298 .push(ctx.provided_type_like_const(*type_ref, const_ty, konst).into());
1299 args.next();
1300 params.next();
1301 } else {
1302 if !had_count_error {
1304 ctx.report_arg_mismatch(param_id, arg_idx as u32, has_self_arg);
1305 }
1306 while args.next().is_some() {}
1307 }
1308 }
1309 _ => {
1310 if !had_count_error {
1315 ctx.report_arg_mismatch(param_id, arg_idx as u32, has_self_arg);
1316 }
1317
1318 while args.next().is_some() {}
1324 }
1325 },
1326
1327 (Some(&(_, arg)), None) => {
1328 if !had_count_error {
1336 assert!(
1337 matches!(arg, HirGenericArg::Lifetime(_)),
1338 "the only possible situation here is incorrect lifetime order"
1339 );
1340 let (provided_arg_idx, param_id) =
1341 force_infer_lt.expect("lifetimes ought to have been inferred");
1342 ctx.report_arg_mismatch(param_id, provided_arg_idx, has_self_arg);
1343 }
1344
1345 break;
1346 }
1347
1348 (None, Some(&(param_id, param))) => {
1349 let param = if let GenericParamId::LifetimeParamId(_) = param_id {
1351 match &lifetime_elision {
1352 LifetimeElisionKind::ElisionFailure
1353 | LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }
1354 | LifetimeElisionKind::AnonymousReportError => {
1355 assert!(had_count_error);
1356 ctx.inferred_kind(
1357 def,
1358 param_id,
1359 param,
1360 infer_args,
1361 &substs,
1362 had_count_error,
1363 )
1364 }
1365 LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
1366 Region::new_static(interner).into()
1367 }
1368 LifetimeElisionKind::Elided(lifetime) => (*lifetime).into(),
1369 LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }
1370 | LifetimeElisionKind::Infer => {
1371 ctx.inferred_kind(
1374 def,
1375 param_id,
1376 param,
1377 infer_args,
1378 &substs,
1379 had_count_error,
1380 )
1381 }
1382 }
1383 } else {
1384 ctx.inferred_kind(def, param_id, param, infer_args, &substs, had_count_error)
1385 };
1386 substs.push(param);
1387 params.next();
1388 }
1389
1390 (None, None) => break,
1391 }
1392 }
1393
1394 GenericArgs::new_from_slice(&substs)
1395}
1396
1397fn type_looks_like_const(
1398 store: &ExpressionStore,
1399 type_ref: TypeRefId,
1400) -> Option<TypeLikeConst<'_>> {
1401 let type_ref = &store[type_ref];
1407 match type_ref {
1408 TypeRef::Path(path) => Some(TypeLikeConst::Path(path)),
1409 TypeRef::Placeholder => Some(TypeLikeConst::Infer),
1410 _ => None,
1411 }
1412}