1use std::ops::ControlFlow;
2
3use rustc_hir as hir;
4use rustc_hir::def::{DefKind, Res};
5use rustc_hir::def_id::DefId;
6use rustc_infer::traits::ObligationCauseCode;
7use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
8use rustc_span::{Span, kw};
9use rustc_trait_selection::traits;
10
11use crate::FnCtxt;
12
13enum ClauseFlavor {
14 Where,
16 Const,
18}
19
20#[derive(#[automatically_derived]
impl ::core::marker::Copy for ParamTerm { }Copy, #[automatically_derived]
impl ::core::clone::Clone for ParamTerm {
#[inline]
fn clone(&self) -> ParamTerm {
let _: ::core::clone::AssertParamIsClone<ty::ParamTy>;
let _: ::core::clone::AssertParamIsClone<ty::ParamConst>;
*self
}
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for ParamTerm {
#[inline]
fn eq(&self, other: &ParamTerm) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(ParamTerm::Ty(__self_0), ParamTerm::Ty(__arg1_0)) =>
__self_0 == __arg1_0,
(ParamTerm::Const(__self_0), ParamTerm::Const(__arg1_0)) =>
__self_0 == __arg1_0,
_ => unsafe { ::core::intrinsics::unreachable() }
}
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ParamTerm {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<ty::ParamTy>;
let _: ::core::cmp::AssertParamIsEq<ty::ParamConst>;
}
}Eq, #[automatically_derived]
impl ::core::fmt::Debug for ParamTerm {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
ParamTerm::Ty(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Ty",
&__self_0),
ParamTerm::Const(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Const",
&__self_0),
}
}
}Debug)]
21enum ParamTerm {
22 Ty(ty::ParamTy),
23 Const(ty::ParamConst),
24}
25
26impl ParamTerm {
27 fn index(self) -> usize {
28 match self {
29 ParamTerm::Ty(ty) => ty.index as usize,
30 ParamTerm::Const(ct) => ct.index as usize,
31 }
32 }
33}
34
35impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
36 pub(crate) fn adjust_fulfillment_error_for_expr_obligation(
37 &self,
38 error: &mut traits::FulfillmentError<'tcx>,
39 ) -> bool {
40 let (def_id, hir_id, idx, flavor) = match *error.obligation.cause.code().peel_derives() {
41 ObligationCauseCode::WhereClauseInExpr(def_id, _, hir_id, idx) => {
42 (def_id, hir_id, idx, ClauseFlavor::Where)
43 }
44 ObligationCauseCode::HostEffectInExpr(def_id, _, hir_id, idx) => {
45 (def_id, hir_id, idx, ClauseFlavor::Const)
46 }
47 _ => return false,
48 };
49
50 let uninstantiated_pred = match flavor {
51 ClauseFlavor::Where
52 if let Some(pred) = self
53 .tcx
54 .predicates_of(def_id)
55 .instantiate_identity(self.tcx)
56 .predicates
57 .into_iter()
58 .nth(idx) =>
59 {
60 pred
61 }
62 ClauseFlavor::Const
63 if let Some((pred, _)) = self
64 .tcx
65 .const_conditions(def_id)
66 .instantiate_identity(self.tcx)
67 .into_iter()
68 .nth(idx) =>
69 {
70 pred.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe)
71 }
72 _ => return false,
73 };
74
75 let generics = self.tcx.generics_of(def_id);
76 let (predicate_args, predicate_self_type_to_point_at) =
77 match uninstantiated_pred.kind().skip_binder() {
78 ty::ClauseKind::Trait(pred) => {
79 (pred.trait_ref.args.to_vec(), Some(pred.self_ty().into()))
80 }
81 ty::ClauseKind::HostEffect(pred) => {
82 (pred.trait_ref.args.to_vec(), Some(pred.self_ty().into()))
83 }
84 ty::ClauseKind::Projection(pred) => (pred.projection_term.args.to_vec(), None),
85 ty::ClauseKind::ConstArgHasType(arg, ty) => (<[_]>::into_vec(::alloc::boxed::box_new([ty.into(), arg.into()]))vec![ty.into(), arg.into()], None),
86 ty::ClauseKind::ConstEvaluatable(e) => (<[_]>::into_vec(::alloc::boxed::box_new([e.into()]))vec![e.into()], None),
87 _ => return false,
88 };
89
90 let find_param_matching = |matches: &dyn Fn(ParamTerm) -> bool| {
91 predicate_args.iter().find_map(|arg| {
92 arg.walk().find(|arg| match arg.kind() {
93 ty::GenericArgKind::Type(ty) if let ty::Param(param_ty) = ty.kind() => {
94 matches(ParamTerm::Ty(*param_ty))
95 }
96 ty::GenericArgKind::Const(ct)
97 if let ty::ConstKind::Param(param_ct) = ct.kind() =>
98 {
99 matches(ParamTerm::Const(param_ct))
100 }
101 _ => false,
102 })
103 })
104 };
105
106 let mut param_to_point_at = find_param_matching(&|param_term| {
109 self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) == def_id
110 });
111 let mut fallback_param_to_point_at = find_param_matching(&|param_term| {
114 self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) != def_id
115 && !#[allow(non_exhaustive_omitted_patterns)] match param_term {
ParamTerm::Ty(ty) if ty.name == kw::SelfUpper => true,
_ => false,
}matches!(param_term, ParamTerm::Ty(ty) if ty.name == kw::SelfUpper)
116 });
117 let mut self_param_to_point_at = find_param_matching(
122 &|param_term| #[allow(non_exhaustive_omitted_patterns)] match param_term {
ParamTerm::Ty(ty) if ty.name == kw::SelfUpper => true,
_ => false,
}matches!(param_term, ParamTerm::Ty(ty) if ty.name == kw::SelfUpper),
123 );
124
125 if let traits::FulfillmentErrorCode::Ambiguity { .. } = error.code {
129 fallback_param_to_point_at = None;
130 self_param_to_point_at = None;
131 param_to_point_at =
132 self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
133 }
134
135 match self.tcx.hir_node(hir_id) {
136 hir::Node::Expr(expr) => self.point_at_expr_if_possible(
137 error,
138 def_id,
139 expr,
140 predicate_self_type_to_point_at,
141 param_to_point_at,
142 fallback_param_to_point_at,
143 self_param_to_point_at,
144 ),
145
146 hir::Node::Ty(hir::Ty { kind: hir::TyKind::Path(qpath), .. }) => {
147 for param in [
148 predicate_self_type_to_point_at,
149 param_to_point_at,
150 fallback_param_to_point_at,
151 self_param_to_point_at,
152 ]
153 .into_iter()
154 .flatten()
155 {
156 if self.point_at_path_if_possible(error, def_id, param, qpath) {
157 return true;
158 }
159 }
160
161 false
162 }
163
164 _ => false,
165 }
166 }
167
168 fn point_at_expr_if_possible(
169 &self,
170 error: &mut traits::FulfillmentError<'tcx>,
171 callee_def_id: DefId,
172 expr: &'tcx hir::Expr<'tcx>,
173 predicate_self_type_to_point_at: Option<ty::GenericArg<'tcx>>,
174 param_to_point_at: Option<ty::GenericArg<'tcx>>,
175 fallback_param_to_point_at: Option<ty::GenericArg<'tcx>>,
176 self_param_to_point_at: Option<ty::GenericArg<'tcx>>,
177 ) -> bool {
178 if self.closure_span_overlaps_error(error, expr.span) {
179 return false;
180 }
181
182 match expr.kind {
183 hir::ExprKind::Call(
184 hir::Expr { kind: hir::ExprKind::Path(qpath), span: callee_span, .. },
185 args,
186 ) => {
187 if let Some(param) = predicate_self_type_to_point_at
188 && self.point_at_path_if_possible(error, callee_def_id, param, qpath)
189 {
190 return true;
191 }
192
193 for param in [
194 predicate_self_type_to_point_at,
195 param_to_point_at,
196 fallback_param_to_point_at,
197 self_param_to_point_at,
198 ]
199 .into_iter()
200 .flatten()
201 {
202 if self.blame_specific_arg_if_possible(
203 error,
204 callee_def_id,
205 param,
206 expr.hir_id,
207 *callee_span,
208 None,
209 args,
210 ) {
211 return true;
212 }
213 }
214
215 for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
216 .into_iter()
217 .flatten()
218 {
219 if self.point_at_path_if_possible(error, callee_def_id, param, qpath) {
220 return true;
221 }
222 }
223 }
224 hir::ExprKind::Path(qpath) => {
225 if let hir::Node::Expr(
231 call_expr @ hir::Expr { kind: hir::ExprKind::Call(callee, ..), .. },
232 ) = self.tcx.parent_hir_node(expr.hir_id)
233 && callee.hir_id == expr.hir_id
234 {
235 return self.point_at_expr_if_possible(
236 error,
237 callee_def_id,
238 call_expr,
239 predicate_self_type_to_point_at,
240 param_to_point_at,
241 fallback_param_to_point_at,
242 self_param_to_point_at,
243 );
244 }
245
246 if let Some(param) = predicate_self_type_to_point_at
249 && self.point_at_path_if_possible(error, callee_def_id, param, &qpath)
250 {
251 return true;
252 }
253
254 for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
255 .into_iter()
256 .flatten()
257 {
258 if self.point_at_path_if_possible(error, callee_def_id, param, &qpath) {
259 return true;
260 }
261 }
262 }
263 hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
264 if let Some(param) = predicate_self_type_to_point_at
265 && self.point_at_generic_if_possible(error, callee_def_id, param, segment)
266 {
267 error.obligation.cause.map_code(|parent_code| {
273 ObligationCauseCode::FunctionArg {
274 arg_hir_id: receiver.hir_id,
275 call_hir_id: expr.hir_id,
276 parent_code,
277 }
278 });
279 return true;
280 }
281
282 for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
283 .into_iter()
284 .flatten()
285 {
286 if self.blame_specific_arg_if_possible(
287 error,
288 callee_def_id,
289 param,
290 expr.hir_id,
291 segment.ident.span,
292 Some(receiver),
293 args,
294 ) {
295 return true;
296 }
297 }
298 if let Some(param_to_point_at) = param_to_point_at
299 && self.point_at_generic_if_possible(
300 error,
301 callee_def_id,
302 param_to_point_at,
303 segment,
304 )
305 {
306 return true;
307 }
308 if self_param_to_point_at.is_some() {
311 error.obligation.cause.span = receiver
312 .span
313 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
314 .unwrap_or(receiver.span);
315 return true;
316 }
317 }
318 hir::ExprKind::Struct(qpath, fields, ..) => {
319 if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) =
320 self.typeck_results.borrow().qpath_res(qpath, expr.hir_id)
321 {
322 for param in
323 [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
324 .into_iter()
325 .flatten()
326 {
327 let refined_expr = self.point_at_field_if_possible(
328 callee_def_id,
329 param,
330 variant_def_id,
331 fields,
332 );
333
334 match refined_expr {
335 None => {}
336 Some((refined_expr, _)) => {
337 error.obligation.cause.span = refined_expr
338 .span
339 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
340 .unwrap_or(refined_expr.span);
341 return true;
342 }
343 }
344 }
345 }
346
347 for param in [
348 predicate_self_type_to_point_at,
349 param_to_point_at,
350 fallback_param_to_point_at,
351 self_param_to_point_at,
352 ]
353 .into_iter()
354 .flatten()
355 {
356 if self.point_at_path_if_possible(error, callee_def_id, param, qpath) {
357 return true;
358 }
359 }
360 }
361 _ => {}
362 }
363
364 false
365 }
366
367 fn point_at_path_if_possible(
368 &self,
369 error: &mut traits::FulfillmentError<'tcx>,
370 def_id: DefId,
371 arg: ty::GenericArg<'tcx>,
372 qpath: &hir::QPath<'tcx>,
373 ) -> bool {
374 match qpath {
375 hir::QPath::Resolved(self_ty, path) => {
376 for segment in path.segments.iter().rev() {
377 if let Res::Def(kind, def_id) = segment.res
378 && !#[allow(non_exhaustive_omitted_patterns)] match kind {
DefKind::Mod | DefKind::ForeignMod => true,
_ => false,
}matches!(kind, DefKind::Mod | DefKind::ForeignMod)
379 && self.point_at_generic_if_possible(error, def_id, arg, segment)
380 {
381 return true;
382 }
383 }
384 if let Some(self_ty) = self_ty
387 && let ty::GenericArgKind::Type(ty) = arg.kind()
388 && ty == self.tcx.types.self_param
389 {
390 error.obligation.cause.span = self_ty
391 .span
392 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
393 .unwrap_or(self_ty.span);
394 return true;
395 }
396 }
397 hir::QPath::TypeRelative(self_ty, segment) => {
398 if self.point_at_generic_if_possible(error, def_id, arg, segment) {
399 return true;
400 }
401 if let ty::GenericArgKind::Type(ty) = arg.kind()
404 && ty == self.tcx.types.self_param
405 {
406 error.obligation.cause.span = self_ty
407 .span
408 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
409 .unwrap_or(self_ty.span);
410 return true;
411 }
412 }
413 }
414
415 false
416 }
417
418 fn point_at_generic_if_possible(
419 &self,
420 error: &mut traits::FulfillmentError<'tcx>,
421 def_id: DefId,
422 param_to_point_at: ty::GenericArg<'tcx>,
423 segment: &hir::PathSegment<'tcx>,
424 ) -> bool {
425 let own_args = self
426 .tcx
427 .generics_of(def_id)
428 .own_args(ty::GenericArgs::identity_for_item(self.tcx, def_id));
429 let Some(mut index) = own_args.iter().position(|arg| *arg == param_to_point_at) else {
430 return false;
431 };
432 let segment_args = segment.args().args;
437 if #[allow(non_exhaustive_omitted_patterns)] match own_args[0].kind() {
ty::GenericArgKind::Lifetime(_) => true,
_ => false,
}matches!(own_args[0].kind(), ty::GenericArgKind::Lifetime(_))
438 && segment_args.first().is_some_and(|arg| arg.is_ty_or_const())
439 && let Some(offset) = own_args.iter().position(|arg| {
440 #[allow(non_exhaustive_omitted_patterns)] match arg.kind() {
ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_) => true,
_ => false,
}matches!(arg.kind(), ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_))
441 })
442 && let Some(new_index) = index.checked_sub(offset)
443 {
444 index = new_index;
445 }
446 let Some(arg) = segment_args.get(index) else {
447 return false;
448 };
449 error.obligation.cause.span = arg
450 .span()
451 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
452 .unwrap_or(arg.span());
453 true
454 }
455
456 fn find_ambiguous_parameter_in<T: TypeVisitable<TyCtxt<'tcx>>>(
457 &self,
458 item_def_id: DefId,
459 t: T,
460 ) -> Option<ty::GenericArg<'tcx>> {
461 struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId);
462 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindAmbiguousParameter<'_, 'tcx> {
463 type Result = ControlFlow<ty::GenericArg<'tcx>>;
464 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
465 if let ty::Infer(ty::TyVar(vid)) = *ty.kind()
466 && let Some(def_id) = self.0.type_var_origin(vid).param_def_id
467 && let generics = self.0.tcx.generics_of(self.1)
468 && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
469 && let Some(arg) =
470 ty::GenericArgs::identity_for_item(self.0.tcx, self.1).get(index as usize)
471 {
472 ControlFlow::Break(*arg)
473 } else {
474 ty.super_visit_with(self)
475 }
476 }
477 }
478 t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value()
479 }
480
481 fn closure_span_overlaps_error(
482 &self,
483 error: &traits::FulfillmentError<'tcx>,
484 span: Span,
485 ) -> bool {
486 if let traits::FulfillmentErrorCode::Select(traits::SelectionError::SignatureMismatch(
487 box traits::SignatureMismatchData { expected_trait_ref, .. },
488 )) = error.code
489 && let ty::Closure(def_id, _) | ty::Coroutine(def_id, ..) =
490 expected_trait_ref.self_ty().kind()
491 && span.overlaps(self.tcx.def_span(*def_id))
492 {
493 true
494 } else {
495 false
496 }
497 }
498
499 fn point_at_field_if_possible(
500 &self,
501 def_id: DefId,
502 param_to_point_at: ty::GenericArg<'tcx>,
503 variant_def_id: DefId,
504 expr_fields: &[hir::ExprField<'tcx>],
505 ) -> Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)> {
506 let def = self.tcx.adt_def(def_id);
507
508 let identity_args = ty::GenericArgs::identity_for_item(self.tcx, def_id);
509 let fields_referencing_param: Vec<_> = def
510 .variant_with_id(variant_def_id)
511 .fields
512 .iter()
513 .filter(|field| {
514 let field_ty = field.ty(self.tcx, identity_args);
515 find_param_in_ty(field_ty.into(), param_to_point_at)
516 })
517 .collect();
518
519 if let [field] = fields_referencing_param.as_slice() {
520 for expr_field in expr_fields {
521 if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx)
524 {
525 return Some((
526 expr_field.expr,
527 self.tcx.type_of(field.did).instantiate_identity(),
528 ));
529 }
530 }
531 }
532
533 None
534 }
535
536 fn blame_specific_arg_if_possible(
546 &self,
547 error: &mut traits::FulfillmentError<'tcx>,
548 def_id: DefId,
549 param_to_point_at: ty::GenericArg<'tcx>,
550 call_hir_id: hir::HirId,
551 callee_span: Span,
552 receiver: Option<&'tcx hir::Expr<'tcx>>,
553 args: &'tcx [hir::Expr<'tcx>],
554 ) -> bool {
555 let ty = self.tcx.type_of(def_id).instantiate_identity();
556 if !ty.is_fn() {
557 return false;
558 }
559 let sig = ty.fn_sig(self.tcx).skip_binder();
560 let args_referencing_param: Vec<_> = sig
561 .inputs()
562 .iter()
563 .enumerate()
564 .filter(|(_, ty)| find_param_in_ty((**ty).into(), param_to_point_at))
565 .collect();
566 if let [(idx, _)] = args_referencing_param.as_slice()
568 && let Some(arg) = receiver.map_or(args.get(*idx), |rcvr| {
569 if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }
570 })
571 {
572 error.obligation.cause.span = arg
573 .span
574 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
575 .unwrap_or(arg.span);
576
577 if let hir::Node::Expr(arg_expr) = self.tcx.hir_node(arg.hir_id) {
578 self.blame_specific_expr_if_possible(error, arg_expr)
580 }
581
582 error.obligation.cause.map_code(|parent_code| ObligationCauseCode::FunctionArg {
583 arg_hir_id: arg.hir_id,
584 call_hir_id,
585 parent_code,
586 });
587 return true;
588 } else if args_referencing_param.len() > 0 {
589 error.obligation.cause.span = callee_span;
592 }
593
594 false
595 }
596
597 pub(crate) fn blame_specific_expr_if_possible(
610 &self,
611 error: &mut traits::FulfillmentError<'tcx>,
612 expr: &'tcx hir::Expr<'tcx>,
613 ) {
614 let expr = match self.blame_specific_expr_if_possible_for_obligation_cause_code(
617 error.obligation.cause.code(),
618 expr,
619 ) {
620 Ok(expr) => expr,
621 Err(expr) => expr,
622 };
623
624 error.obligation.cause.span = expr
628 .span
629 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
630 .unwrap_or(error.obligation.cause.span);
631 }
632
633 fn blame_specific_expr_if_possible_for_obligation_cause_code(
634 &self,
635 obligation_cause_code: &traits::ObligationCauseCode<'tcx>,
636 expr: &'tcx hir::Expr<'tcx>,
637 ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
638 match obligation_cause_code {
639 traits::ObligationCauseCode::WhereClauseInExpr(_, _, _, _)
640 | ObligationCauseCode::HostEffectInExpr(..) => {
641 Ok(expr)
644 }
645 traits::ObligationCauseCode::ImplDerived(impl_derived) => self
646 .blame_specific_expr_if_possible_for_derived_predicate_obligation(
647 impl_derived,
648 expr,
649 ),
650 _ => {
651 Err(expr)
654 }
655 }
656 }
657
658 fn blame_specific_expr_if_possible_for_derived_predicate_obligation(
682 &self,
683 obligation: &traits::ImplDerivedCause<'tcx>,
684 expr: &'tcx hir::Expr<'tcx>,
685 ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
686 let expr = self.blame_specific_expr_if_possible_for_obligation_cause_code(
690 &*obligation.derived.parent_code,
691 expr,
692 )?;
693
694 let impl_trait_self_ref = if self.tcx.is_trait_alias(obligation.impl_or_alias_def_id) {
698 ty::TraitRef::new_from_args(
699 self.tcx,
700 obligation.impl_or_alias_def_id,
701 ty::GenericArgs::identity_for_item(self.tcx, obligation.impl_or_alias_def_id),
702 )
703 } else {
704 self.tcx
705 .impl_opt_trait_ref(obligation.impl_or_alias_def_id)
706 .map(|impl_def| impl_def.skip_binder())
707 .ok_or(expr)?
709 };
710
711 let impl_self_ty: Ty<'tcx> = impl_trait_self_ref.self_ty();
713
714 let impl_predicates: ty::GenericPredicates<'tcx> =
715 self.tcx.predicates_of(obligation.impl_or_alias_def_id);
716 let Some(impl_predicate_index) = obligation.impl_def_predicate_index else {
717 return Err(expr);
719 };
720
721 if impl_predicate_index >= impl_predicates.predicates.len() {
722 return Err(expr);
724 }
725
726 match impl_predicates.predicates[impl_predicate_index].0.kind().skip_binder() {
727 ty::ClauseKind::Trait(broken_trait) => {
728 self.blame_specific_part_of_expr_corresponding_to_generic_param(
730 broken_trait.trait_ref.self_ty().into(),
731 expr,
732 impl_self_ty.into(),
733 )
734 }
735 _ => Err(expr),
736 }
737 }
738
739 fn blame_specific_part_of_expr_corresponding_to_generic_param(
755 &self,
756 param: ty::GenericArg<'tcx>,
757 expr: &'tcx hir::Expr<'tcx>,
758 in_ty: ty::GenericArg<'tcx>,
759 ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
760 if param == in_ty {
761 return Ok(expr);
763 }
764
765 let ty::GenericArgKind::Type(in_ty) = in_ty.kind() else {
766 return Err(expr);
767 };
768
769 if let (
770 hir::ExprKind::AddrOf(_borrow_kind, _borrow_mutability, borrowed_expr),
771 ty::Ref(_ty_region, ty_ref_type, _ty_mutability),
772 ) = (&expr.kind, in_ty.kind())
773 {
774 return self.blame_specific_part_of_expr_corresponding_to_generic_param(
776 param,
777 borrowed_expr,
778 (*ty_ref_type).into(),
779 );
780 }
781
782 if let (hir::ExprKind::Tup(expr_elements), ty::Tuple(in_ty_elements)) =
783 (&expr.kind, in_ty.kind())
784 {
785 if in_ty_elements.len() != expr_elements.len() {
786 return Err(expr);
787 }
788 let Some((drill_expr, drill_ty)) =
792 is_iterator_singleton(expr_elements.iter().zip(in_ty_elements.iter()).filter(
793 |(_expr_elem, in_ty_elem)| find_param_in_ty((*in_ty_elem).into(), param),
794 ))
795 else {
796 return Err(expr);
798 };
799
800 return self.blame_specific_part_of_expr_corresponding_to_generic_param(
801 param,
802 drill_expr,
803 drill_ty.into(),
804 );
805 }
806
807 if let (
808 hir::ExprKind::Struct(expr_struct_path, expr_struct_fields, _expr_struct_rest),
809 ty::Adt(in_ty_adt, in_ty_adt_generic_args),
810 ) = (&expr.kind, in_ty.kind())
811 {
812 let Res::Def(expr_struct_def_kind, expr_struct_def_id) =
815 self.typeck_results.borrow().qpath_res(expr_struct_path, expr.hir_id)
816 else {
817 return Err(expr);
818 };
819
820 let variant_def_id = match expr_struct_def_kind {
821 DefKind::Struct => {
822 if in_ty_adt.did() != expr_struct_def_id {
823 return Err(expr);
825 }
826 expr_struct_def_id
827 }
828 DefKind::Variant => {
829 if in_ty_adt.did() != self.tcx.parent(expr_struct_def_id) {
831 return Err(expr);
833 }
834 expr_struct_def_id
835 }
836 _ => {
837 return Err(expr);
838 }
839 };
840
841 let Some((drill_generic_index, generic_argument_type)) = is_iterator_singleton(
844 in_ty_adt_generic_args
845 .iter()
846 .enumerate()
847 .filter(|(_index, in_ty_generic)| find_param_in_ty(*in_ty_generic, param)),
848 ) else {
849 return Err(expr);
850 };
851
852 let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did());
853 if drill_generic_index >= struct_generic_parameters.own_params.len() {
854 return Err(expr);
855 }
856
857 let param_to_point_at_in_struct = self.tcx.mk_param_from_def(
858 struct_generic_parameters.param_at(drill_generic_index, self.tcx),
859 );
860
861 let (field_expr, field_type) = self
885 .point_at_field_if_possible(
886 in_ty_adt.did(),
887 param_to_point_at_in_struct,
888 variant_def_id,
889 expr_struct_fields,
890 )
891 .ok_or(expr)?;
892
893 let expr = self.blame_specific_part_of_expr_corresponding_to_generic_param(
896 param_to_point_at_in_struct,
897 field_expr,
898 field_type.into(),
899 )?;
900
901 return self.blame_specific_part_of_expr_corresponding_to_generic_param(
904 param,
905 expr,
906 generic_argument_type,
907 );
908 }
909
910 if let (
911 hir::ExprKind::Call(expr_callee, expr_args),
912 ty::Adt(in_ty_adt, in_ty_adt_generic_args),
913 ) = (&expr.kind, in_ty.kind())
914 {
915 let hir::ExprKind::Path(expr_callee_path) = &expr_callee.kind else {
916 return Err(expr);
920 };
921 let Res::Def(expr_struct_def_kind, expr_ctor_def_id) =
924 self.typeck_results.borrow().qpath_res(expr_callee_path, expr_callee.hir_id)
925 else {
926 return Err(expr);
927 };
928
929 let variant_def_id = match expr_struct_def_kind {
930 DefKind::Ctor(hir::def::CtorOf::Struct, hir::def::CtorKind::Fn) => {
931 if in_ty_adt.did() != self.tcx.parent(expr_ctor_def_id) {
932 return Err(expr);
934 }
935 self.tcx.parent(expr_ctor_def_id)
936 }
937 DefKind::Ctor(hir::def::CtorOf::Variant, hir::def::CtorKind::Fn) => {
938 if in_ty_adt.did() == self.tcx.parent(self.tcx.parent(expr_ctor_def_id)) {
951 self.tcx.parent(expr_ctor_def_id)
954 } else {
955 return Err(expr);
957 }
958 }
959 _ => {
960 return Err(expr);
961 }
962 };
963
964 let Some((drill_generic_index, generic_argument_type)) = is_iterator_singleton(
967 in_ty_adt_generic_args
968 .iter()
969 .enumerate()
970 .filter(|(_index, in_ty_generic)| find_param_in_ty(*in_ty_generic, param)),
971 ) else {
972 return Err(expr);
973 };
974
975 let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did());
976 if drill_generic_index >= struct_generic_parameters.own_params.len() {
977 return Err(expr);
978 }
979
980 let param_to_point_at_in_struct = self.tcx.mk_param_from_def(
981 struct_generic_parameters.param_at(drill_generic_index, self.tcx),
982 );
983
984 let Some((field_index, field_type)) = is_iterator_singleton(
1008 in_ty_adt
1009 .variant_with_id(variant_def_id)
1010 .fields
1011 .iter()
1012 .map(|field| field.ty(self.tcx, in_ty_adt_generic_args))
1013 .enumerate()
1014 .filter(|(_index, field_type)| find_param_in_ty((*field_type).into(), param)),
1015 ) else {
1016 return Err(expr);
1017 };
1018
1019 if field_index >= expr_args.len() {
1020 return Err(expr);
1021 }
1022
1023 let expr = self.blame_specific_part_of_expr_corresponding_to_generic_param(
1026 param_to_point_at_in_struct,
1027 &expr_args[field_index],
1028 field_type.into(),
1029 )?;
1030
1031 return self.blame_specific_part_of_expr_corresponding_to_generic_param(
1034 param,
1035 expr,
1036 generic_argument_type,
1037 );
1038 }
1039
1040 Err(expr)
1046 }
1047}
1048
1049fn find_param_in_ty<'tcx>(
1052 ty: ty::GenericArg<'tcx>,
1053 param_to_point_at: ty::GenericArg<'tcx>,
1054) -> bool {
1055 let mut walk = ty.walk();
1056 while let Some(arg) = walk.next() {
1057 if arg == param_to_point_at {
1058 return true;
1059 }
1060 if let ty::GenericArgKind::Type(ty) = arg.kind()
1061 && let ty::Alias(ty::Projection | ty::Inherent, ..) = ty.kind()
1062 {
1063 walk.skip_current_subtree();
1070 }
1071 }
1072 false
1073}
1074
1075fn is_iterator_singleton<T>(mut iterator: impl Iterator<Item = T>) -> Option<T> {
1077 match (iterator.next(), iterator.next()) {
1078 (_, Some(_)) => None,
1079 (first, _) => first,
1080 }
1081}