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::{
8 self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
9};
10use rustc_span::{Span, kw};
11use rustc_trait_selection::infer::InferCtxtExt;
12use rustc_trait_selection::traits;
13
14use crate::FnCtxt;
15
16enum ClauseFlavor {
17 Where,
19 Const,
21}
22
23#[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_fields_are_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)]
24enum ParamTerm {
25 Ty(ty::ParamTy),
26 Const(ty::ParamConst),
27}
28
29impl ParamTerm {
30 fn index(self) -> usize {
31 match self {
32 ParamTerm::Ty(ty) => ty.index as usize,
33 ParamTerm::Const(ct) => ct.index as usize,
34 }
35 }
36}
37
38impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
39 pub(crate) fn adjust_fulfillment_error_for_expr_obligation(
40 &self,
41 error: &mut traits::FulfillmentError<'tcx>,
42 ) -> bool {
43 if self.adjust_binop_index_operand(error) {
44 return true;
45 }
46
47 let (def_id, hir_id, idx, flavor) = match *error.obligation.cause.code().peel_derives() {
48 ObligationCauseCode::WhereClauseInExpr(def_id, _, hir_id, idx) => {
49 (def_id, hir_id, idx, ClauseFlavor::Where)
50 }
51 ObligationCauseCode::HostEffectInExpr(def_id, _, hir_id, idx) => {
52 (def_id, hir_id, idx, ClauseFlavor::Const)
53 }
54 _ => return false,
55 };
56
57 let uninstantiated_pred = match flavor {
58 ClauseFlavor::Where
59 if let Some(pred) = self
60 .tcx
61 .predicates_of(def_id)
62 .instantiate_identity(self.tcx)
63 .predicates
64 .into_iter()
65 .nth(idx) =>
66 {
67 pred
68 }
69 ClauseFlavor::Const
70 if let Some((pred, _)) = self
71 .tcx
72 .const_conditions(def_id)
73 .instantiate_identity(self.tcx)
74 .into_iter()
75 .nth(idx) =>
76 {
77 pred.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe)
78 }
79 _ => return false,
80 };
81
82 let generics = self.tcx.generics_of(def_id);
83 let (predicate_args, predicate_self_type_to_point_at) =
84 match uninstantiated_pred.kind().skip_binder() {
85 ty::ClauseKind::Trait(pred) => {
86 (pred.trait_ref.args.to_vec(), Some(pred.self_ty().into()))
87 }
88 ty::ClauseKind::HostEffect(pred) => {
89 (pred.trait_ref.args.to_vec(), Some(pred.self_ty().into()))
90 }
91 ty::ClauseKind::Projection(pred) => (pred.projection_term.args.to_vec(), None),
92 ty::ClauseKind::ConstArgHasType(arg, ty) => (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[ty.into(), arg.into()]))vec![ty.into(), arg.into()], None),
93 ty::ClauseKind::ConstEvaluatable(e) => (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[e.into()]))vec![e.into()], None),
94 _ => return false,
95 };
96
97 let find_param_matching = |matches: &dyn Fn(ParamTerm) -> bool| {
98 predicate_args.iter().find_map(|arg| {
99 arg.walk().find(|arg| match arg.kind() {
100 ty::GenericArgKind::Type(ty) if let ty::Param(param_ty) = ty.kind() => {
101 matches(ParamTerm::Ty(*param_ty))
102 }
103 ty::GenericArgKind::Const(ct)
104 if let ty::ConstKind::Param(param_ct) = ct.kind() =>
105 {
106 matches(ParamTerm::Const(param_ct))
107 }
108 _ => false,
109 })
110 })
111 };
112
113 let mut param_to_point_at = find_param_matching(&|param_term| {
116 self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) == def_id
117 });
118 let mut fallback_param_to_point_at = find_param_matching(&|param_term| {
121 self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) != def_id
122 && !#[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 let mut self_param_to_point_at = find_param_matching(
129 &|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),
130 );
131
132 if let traits::FulfillmentErrorCode::Ambiguity { .. } = error.code {
136 fallback_param_to_point_at = None;
137 self_param_to_point_at = None;
138 param_to_point_at =
139 self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
140 }
141
142 match self.tcx.hir_node(hir_id) {
143 hir::Node::Expr(expr) => self.point_at_expr_if_possible(
144 error,
145 def_id,
146 expr,
147 predicate_self_type_to_point_at,
148 param_to_point_at,
149 fallback_param_to_point_at,
150 self_param_to_point_at,
151 ),
152
153 hir::Node::Ty(hir::Ty { kind: hir::TyKind::Path(qpath), .. }) => {
154 for param in [
155 predicate_self_type_to_point_at,
156 param_to_point_at,
157 fallback_param_to_point_at,
158 self_param_to_point_at,
159 ]
160 .into_iter()
161 .flatten()
162 {
163 if self.point_at_path_if_possible(error, def_id, param, qpath) {
164 return true;
165 }
166 }
167
168 false
169 }
170
171 _ => false,
172 }
173 }
174
175 fn adjust_binop_index_operand(&self, error: &mut traits::FulfillmentError<'tcx>) -> bool {
176 let ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, .. } =
177 *error.obligation.cause.code().peel_derives()
178 else {
179 return false;
180 };
181 if !#[allow(non_exhaustive_omitted_patterns)] match error.code {
traits::FulfillmentErrorCode::Ambiguity { .. } => true,
_ => false,
}matches!(error.code, traits::FulfillmentErrorCode::Ambiguity { .. })
182 || !error.obligation.predicate.has_infer()
183 {
184 return false;
185 }
186
187 let hir::Node::Expr(lhs_expr) = self.tcx.hir_node(lhs_hir_id) else {
188 return false;
189 };
190 let hir::Node::Expr(rhs_expr) = self.tcx.hir_node(rhs_hir_id) else {
191 return false;
192 };
193 let Some(binop) = self.binop_for_operands(lhs_hir_id, rhs_hir_id) else {
194 return false;
195 };
196 let hir::ExprKind::Index(indexed_expr, idx, _) = rhs_expr.kind else {
197 return false;
198 };
199 if !self.resolve_vars_if_possible(self.node_ty(idx.hir_id)).is_ty_var() {
200 return false;
201 }
202 let lhs_ty = self.resolve_vars_if_possible(self.node_ty(lhs_expr.hir_id));
203 let indexed_ty = self.resolve_vars_if_possible(self.node_ty(indexed_expr.hir_id));
204 let rhs_ty = match *indexed_ty.kind() {
205 ty::Array(element_ty, _) | ty::Slice(element_ty) => element_ty,
206 ty::Ref(_, pointee_ty, _) => match *pointee_ty.kind() {
207 ty::Array(element_ty, _) | ty::Slice(element_ty) => element_ty,
208 _ => self.resolve_vars_if_possible(self.node_ty(rhs_expr.hir_id)),
209 },
210 _ => self.resolve_vars_if_possible(self.node_ty(rhs_expr.hir_id)),
211 };
212 if !self.binop_accepts_types(binop.node, lhs_ty, rhs_ty) {
213 return false;
214 }
215
216 error.obligation.cause.span = match idx.kind {
217 hir::ExprKind::MethodCall(segment, ..) => segment.ident.span,
218 _ => idx.span,
219 };
220 true
221 }
222
223 fn binop_for_operands(
224 &self,
225 lhs_hir_id: hir::HirId,
226 rhs_hir_id: hir::HirId,
227 ) -> Option<hir::BinOp> {
228 let hir::Node::Expr(parent_expr) = self.tcx.parent_hir_node(rhs_hir_id) else {
229 return None;
230 };
231 let hir::ExprKind::Binary(binop, lhs_expr, rhs_expr) = parent_expr.kind else {
232 return None;
233 };
234 (lhs_expr.hir_id == lhs_hir_id && rhs_expr.hir_id == rhs_hir_id).then_some(binop)
235 }
236
237 fn binop_accepts_types(
238 &self,
239 binop: hir::BinOpKind,
240 lhs_ty: Ty<'tcx>,
241 rhs_ty: Ty<'tcx>,
242 ) -> bool {
243 let lhs_ty = self.deref_ty_if_possible(lhs_ty);
244 let rhs_ty = self.deref_ty_if_possible(rhs_ty);
245 if lhs_ty.references_error() || rhs_ty.references_error() {
246 return true;
247 }
248
249 match binop {
250 hir::BinOpKind::Shl | hir::BinOpKind::Shr => {
251 lhs_ty.is_integral() && rhs_ty.is_integral()
252 }
253 hir::BinOpKind::Add
254 | hir::BinOpKind::Sub
255 | hir::BinOpKind::Mul
256 | hir::BinOpKind::Div
257 | hir::BinOpKind::Rem => {
258 self.can_eq(self.param_env, lhs_ty, rhs_ty)
259 && (lhs_ty.is_integral() || lhs_ty.is_floating_point())
260 && (rhs_ty.is_integral() || rhs_ty.is_floating_point())
261 }
262 hir::BinOpKind::BitXor | hir::BinOpKind::BitAnd | hir::BinOpKind::BitOr => {
263 self.can_eq(self.param_env, lhs_ty, rhs_ty)
264 && ((lhs_ty.is_integral() && rhs_ty.is_integral())
265 || (lhs_ty.is_bool() && rhs_ty.is_bool()))
266 }
267 hir::BinOpKind::Eq
268 | hir::BinOpKind::Ne
269 | hir::BinOpKind::Lt
270 | hir::BinOpKind::Le
271 | hir::BinOpKind::Ge
272 | hir::BinOpKind::Gt => {
273 self.can_eq(self.param_env, lhs_ty, rhs_ty)
274 && lhs_ty.is_scalar()
275 && rhs_ty.is_scalar()
276 }
277 hir::BinOpKind::And | hir::BinOpKind::Or => lhs_ty.is_bool() && rhs_ty.is_bool(),
278 }
279 }
280
281 fn deref_ty_if_possible(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
282 match ty.kind() {
283 ty::Ref(_, ty, hir::Mutability::Not) => *ty,
284 _ => ty,
285 }
286 }
287
288 fn point_at_expr_if_possible(
289 &self,
290 error: &mut traits::FulfillmentError<'tcx>,
291 callee_def_id: DefId,
292 expr: &'tcx hir::Expr<'tcx>,
293 predicate_self_type_to_point_at: Option<ty::GenericArg<'tcx>>,
294 param_to_point_at: Option<ty::GenericArg<'tcx>>,
295 fallback_param_to_point_at: Option<ty::GenericArg<'tcx>>,
296 self_param_to_point_at: Option<ty::GenericArg<'tcx>>,
297 ) -> bool {
298 if self.closure_span_overlaps_error(error, expr.span) {
299 return false;
300 }
301
302 match expr.kind {
303 hir::ExprKind::Call(
304 hir::Expr { kind: hir::ExprKind::Path(qpath), span: callee_span, .. },
305 args,
306 ) => {
307 if let Some(param) = predicate_self_type_to_point_at
308 && self.point_at_path_if_possible(error, callee_def_id, param, qpath)
309 {
310 return true;
311 }
312
313 for param in [
314 predicate_self_type_to_point_at,
315 param_to_point_at,
316 fallback_param_to_point_at,
317 self_param_to_point_at,
318 ]
319 .into_iter()
320 .flatten()
321 {
322 if self.blame_specific_arg_if_possible(
323 error,
324 callee_def_id,
325 param,
326 expr.hir_id,
327 *callee_span,
328 None,
329 args,
330 ) {
331 return true;
332 }
333 }
334
335 for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
336 .into_iter()
337 .flatten()
338 {
339 if self.point_at_path_if_possible(error, callee_def_id, param, qpath) {
340 return true;
341 }
342 }
343 }
344 hir::ExprKind::Path(qpath) => {
345 if let hir::Node::Expr(
351 call_expr @ hir::Expr { kind: hir::ExprKind::Call(callee, ..), .. },
352 ) = self.tcx.parent_hir_node(expr.hir_id)
353 && callee.hir_id == expr.hir_id
354 {
355 return self.point_at_expr_if_possible(
356 error,
357 callee_def_id,
358 call_expr,
359 predicate_self_type_to_point_at,
360 param_to_point_at,
361 fallback_param_to_point_at,
362 self_param_to_point_at,
363 );
364 }
365
366 if let Some(param) = predicate_self_type_to_point_at
369 && self.point_at_path_if_possible(error, callee_def_id, param, &qpath)
370 {
371 return true;
372 }
373
374 for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
375 .into_iter()
376 .flatten()
377 {
378 if self.point_at_path_if_possible(error, callee_def_id, param, &qpath) {
379 return true;
380 }
381 }
382 }
383 hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
384 if let Some(param) = predicate_self_type_to_point_at
385 && self.point_at_generic_if_possible(error, callee_def_id, param, segment)
386 {
387 error.obligation.cause.map_code(|parent_code| {
393 ObligationCauseCode::FunctionArg {
394 arg_hir_id: receiver.hir_id,
395 call_hir_id: expr.hir_id,
396 parent_code,
397 }
398 });
399 return true;
400 }
401
402 for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
403 .into_iter()
404 .flatten()
405 {
406 if self.blame_specific_arg_if_possible(
407 error,
408 callee_def_id,
409 param,
410 expr.hir_id,
411 segment.ident.span,
412 Some(receiver),
413 args,
414 ) {
415 return true;
416 }
417 }
418 if let Some(param_to_point_at) = param_to_point_at
419 && self.point_at_generic_if_possible(
420 error,
421 callee_def_id,
422 param_to_point_at,
423 segment,
424 )
425 {
426 return true;
427 }
428 if self_param_to_point_at.is_some() {
431 error.obligation.cause.span = receiver
432 .span
433 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
434 .unwrap_or(receiver.span);
435 return true;
436 }
437 }
438 hir::ExprKind::Struct(qpath, fields, ..) => {
439 if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) =
440 self.typeck_results.borrow().qpath_res(qpath, expr.hir_id)
441 {
442 for param in
443 [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
444 .into_iter()
445 .flatten()
446 {
447 let refined_expr = self.point_at_field_if_possible(
448 callee_def_id,
449 param,
450 variant_def_id,
451 fields,
452 );
453
454 match refined_expr {
455 None => {}
456 Some((refined_expr, _)) => {
457 error.obligation.cause.span = refined_expr
458 .span
459 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
460 .unwrap_or(refined_expr.span);
461 return true;
462 }
463 }
464 }
465 }
466
467 for param in [
468 predicate_self_type_to_point_at,
469 param_to_point_at,
470 fallback_param_to_point_at,
471 self_param_to_point_at,
472 ]
473 .into_iter()
474 .flatten()
475 {
476 if self.point_at_path_if_possible(error, callee_def_id, param, qpath) {
477 return true;
478 }
479 }
480 }
481 _ => {}
482 }
483
484 false
485 }
486
487 fn point_at_path_if_possible(
488 &self,
489 error: &mut traits::FulfillmentError<'tcx>,
490 def_id: DefId,
491 arg: ty::GenericArg<'tcx>,
492 qpath: &hir::QPath<'tcx>,
493 ) -> bool {
494 match qpath {
495 hir::QPath::Resolved(self_ty, path) => {
496 for segment in path.segments.iter().rev() {
497 if let Res::Def(kind, def_id) = segment.res
498 && !#[allow(non_exhaustive_omitted_patterns)] match kind {
DefKind::Mod | DefKind::ForeignMod => true,
_ => false,
}matches!(kind, DefKind::Mod | DefKind::ForeignMod)
499 && self.point_at_generic_if_possible(error, def_id, arg, segment)
500 {
501 return true;
502 }
503 }
504 if let Some(self_ty) = self_ty
507 && let ty::GenericArgKind::Type(ty) = arg.kind()
508 && ty == self.tcx.types.self_param
509 {
510 error.obligation.cause.span = self_ty
511 .span
512 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
513 .unwrap_or(self_ty.span);
514 return true;
515 }
516 }
517 hir::QPath::TypeRelative(self_ty, segment) => {
518 if self.point_at_generic_if_possible(error, def_id, arg, segment) {
519 return true;
520 }
521 if let ty::GenericArgKind::Type(ty) = arg.kind()
524 && ty == self.tcx.types.self_param
525 {
526 error.obligation.cause.span = self_ty
527 .span
528 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
529 .unwrap_or(self_ty.span);
530 return true;
531 }
532 }
533 }
534
535 false
536 }
537
538 fn point_at_generic_if_possible(
539 &self,
540 error: &mut traits::FulfillmentError<'tcx>,
541 def_id: DefId,
542 param_to_point_at: ty::GenericArg<'tcx>,
543 segment: &hir::PathSegment<'tcx>,
544 ) -> bool {
545 let own_args = self
546 .tcx
547 .generics_of(def_id)
548 .own_args(ty::GenericArgs::identity_for_item(self.tcx, def_id));
549 let Some(mut index) = own_args.iter().position(|arg| *arg == param_to_point_at) else {
550 return false;
551 };
552 let segment_args = segment.args().args;
557 if #[allow(non_exhaustive_omitted_patterns)] match own_args[0].kind() {
ty::GenericArgKind::Lifetime(_) => true,
_ => false,
}matches!(own_args[0].kind(), ty::GenericArgKind::Lifetime(_))
558 && segment_args.first().is_some_and(|arg| arg.is_ty_or_const())
559 && let Some(offset) = own_args.iter().position(|arg| {
560 #[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(_))
561 })
562 && let Some(new_index) = index.checked_sub(offset)
563 {
564 index = new_index;
565 }
566 let Some(arg) = segment_args.get(index) else {
567 return false;
568 };
569 error.obligation.cause.span = arg
570 .span()
571 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
572 .unwrap_or(arg.span());
573 true
574 }
575
576 fn find_ambiguous_parameter_in<T: TypeVisitable<TyCtxt<'tcx>>>(
577 &self,
578 item_def_id: DefId,
579 t: T,
580 ) -> Option<ty::GenericArg<'tcx>> {
581 struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId);
582 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindAmbiguousParameter<'_, 'tcx> {
583 type Result = ControlFlow<ty::GenericArg<'tcx>>;
584 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
585 if let ty::Infer(ty::TyVar(vid)) = *ty.kind()
586 && let Some(def_id) = self.0.type_var_origin(vid).param_def_id
587 && let generics = self.0.tcx.generics_of(self.1)
588 && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
589 && let Some(arg) =
590 ty::GenericArgs::identity_for_item(self.0.tcx, self.1).get(index as usize)
591 {
592 ControlFlow::Break(*arg)
593 } else {
594 ty.super_visit_with(self)
595 }
596 }
597 }
598 t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value()
599 }
600
601 fn closure_span_overlaps_error(
602 &self,
603 error: &traits::FulfillmentError<'tcx>,
604 span: Span,
605 ) -> bool {
606 if let traits::FulfillmentErrorCode::Select(traits::SelectionError::SignatureMismatch(
607 traits::SignatureMismatchData { expected_trait_ref, .. },
608 )) = error.code
609 && let ty::Closure(def_id, _) | ty::Coroutine(def_id, ..) =
610 expected_trait_ref.self_ty().kind()
611 && span.overlaps(self.tcx.def_span(*def_id))
612 {
613 true
614 } else {
615 false
616 }
617 }
618
619 fn point_at_field_if_possible(
620 &self,
621 def_id: DefId,
622 param_to_point_at: ty::GenericArg<'tcx>,
623 variant_def_id: DefId,
624 expr_fields: &[hir::ExprField<'tcx>],
625 ) -> Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)> {
626 let def = self.tcx.adt_def(def_id);
627
628 let identity_args = ty::GenericArgs::identity_for_item(self.tcx, def_id);
629 let fields_referencing_param: Vec<_> = def
630 .variant_with_id(variant_def_id)
631 .fields
632 .iter()
633 .filter(|field| {
634 let field_ty = field.ty(self.tcx, identity_args).skip_norm_wip();
635 find_param_in_ty(field_ty.into(), param_to_point_at)
636 })
637 .collect();
638
639 if let [field] = fields_referencing_param.as_slice() {
640 for expr_field in expr_fields {
641 if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx)
644 {
645 return Some((
646 expr_field.expr,
647 self.tcx.type_of(field.did).instantiate_identity().skip_norm_wip(),
648 ));
649 }
650 }
651 }
652
653 None
654 }
655
656 fn blame_specific_arg_if_possible(
666 &self,
667 error: &mut traits::FulfillmentError<'tcx>,
668 def_id: DefId,
669 param_to_point_at: ty::GenericArg<'tcx>,
670 call_hir_id: hir::HirId,
671 callee_span: Span,
672 receiver: Option<&'tcx hir::Expr<'tcx>>,
673 args: &'tcx [hir::Expr<'tcx>],
674 ) -> bool {
675 let ty = self.tcx.type_of(def_id).instantiate_identity().skip_norm_wip();
676 if !ty.is_fn() {
677 return false;
678 }
679 let sig = ty.fn_sig(self.tcx).skip_binder();
680 let args_referencing_param: Vec<_> = sig
681 .inputs()
682 .iter()
683 .enumerate()
684 .filter(|(_, ty)| find_param_in_ty((**ty).into(), param_to_point_at))
685 .collect();
686 if let [(idx, _)] = args_referencing_param.as_slice()
688 && let Some(arg) = receiver.map_or(args.get(*idx), |rcvr| {
689 if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }
690 })
691 {
692 error.obligation.cause.span = arg
693 .span
694 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
695 .unwrap_or(arg.span);
696
697 if let hir::Node::Expr(arg_expr) = self.tcx.hir_node(arg.hir_id) {
698 self.blame_specific_expr_if_possible(error, arg_expr)
700 }
701
702 error.obligation.cause.map_code(|parent_code| ObligationCauseCode::FunctionArg {
703 arg_hir_id: arg.hir_id,
704 call_hir_id,
705 parent_code,
706 });
707 return true;
708 } else if args_referencing_param.len() > 0 {
709 error.obligation.cause.span = callee_span;
712 }
713
714 false
715 }
716
717 pub(crate) fn blame_specific_expr_if_possible(
730 &self,
731 error: &mut traits::FulfillmentError<'tcx>,
732 expr: &'tcx hir::Expr<'tcx>,
733 ) {
734 let expr = match self.blame_specific_expr_if_possible_for_obligation_cause_code(
737 error.obligation.cause.code(),
738 expr,
739 ) {
740 Ok(expr) => expr,
741 Err(expr) => expr,
742 };
743
744 error.obligation.cause.span = expr
748 .span
749 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
750 .unwrap_or(error.obligation.cause.span);
751 }
752
753 fn blame_specific_expr_if_possible_for_obligation_cause_code(
754 &self,
755 obligation_cause_code: &traits::ObligationCauseCode<'tcx>,
756 expr: &'tcx hir::Expr<'tcx>,
757 ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
758 match obligation_cause_code {
759 traits::ObligationCauseCode::WhereClauseInExpr(_, _, _, _)
760 | ObligationCauseCode::HostEffectInExpr(..) => {
761 Ok(expr)
764 }
765 traits::ObligationCauseCode::ImplDerived(impl_derived) => self
766 .blame_specific_expr_if_possible_for_derived_predicate_obligation(
767 impl_derived,
768 expr,
769 ),
770 _ => {
771 Err(expr)
774 }
775 }
776 }
777
778 fn blame_specific_expr_if_possible_for_derived_predicate_obligation(
802 &self,
803 obligation: &traits::ImplDerivedCause<'tcx>,
804 expr: &'tcx hir::Expr<'tcx>,
805 ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
806 let expr = self.blame_specific_expr_if_possible_for_obligation_cause_code(
810 &*obligation.derived.parent_code,
811 expr,
812 )?;
813
814 let impl_trait_self_ref = if self.tcx.is_trait_alias(obligation.impl_or_alias_def_id) {
818 ty::TraitRef::new_from_args(
819 self.tcx,
820 obligation.impl_or_alias_def_id,
821 ty::GenericArgs::identity_for_item(self.tcx, obligation.impl_or_alias_def_id),
822 )
823 } else {
824 self.tcx
825 .impl_opt_trait_ref(obligation.impl_or_alias_def_id)
826 .map(|impl_def| impl_def.skip_binder())
827 .ok_or(expr)?
829 };
830
831 let impl_self_ty: Ty<'tcx> = impl_trait_self_ref.self_ty();
833
834 let impl_predicates: ty::GenericPredicates<'tcx> =
835 self.tcx.predicates_of(obligation.impl_or_alias_def_id);
836 let Some(impl_predicate_index) = obligation.impl_def_predicate_index else {
837 return Err(expr);
839 };
840
841 if impl_predicate_index >= impl_predicates.predicates.len() {
842 return Err(expr);
844 }
845
846 match impl_predicates.predicates[impl_predicate_index].0.kind().skip_binder() {
847 ty::ClauseKind::Trait(broken_trait) => {
848 self.blame_specific_part_of_expr_corresponding_to_generic_param(
850 broken_trait.trait_ref.self_ty().into(),
851 expr,
852 impl_self_ty.into(),
853 )
854 }
855 _ => Err(expr),
856 }
857 }
858
859 fn blame_specific_part_of_expr_corresponding_to_generic_param(
875 &self,
876 param: ty::GenericArg<'tcx>,
877 expr: &'tcx hir::Expr<'tcx>,
878 in_ty: ty::GenericArg<'tcx>,
879 ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
880 if param == in_ty {
881 return Ok(expr);
883 }
884
885 let ty::GenericArgKind::Type(in_ty) = in_ty.kind() else {
886 return Err(expr);
887 };
888
889 if let (
890 hir::ExprKind::AddrOf(_borrow_kind, _borrow_mutability, borrowed_expr),
891 ty::Ref(_ty_region, ty_ref_type, _ty_mutability),
892 ) = (&expr.kind, in_ty.kind())
893 {
894 return self.blame_specific_part_of_expr_corresponding_to_generic_param(
896 param,
897 borrowed_expr,
898 (*ty_ref_type).into(),
899 );
900 }
901
902 if let (hir::ExprKind::Tup(expr_elements), ty::Tuple(in_ty_elements)) =
903 (&expr.kind, in_ty.kind())
904 {
905 if in_ty_elements.len() != expr_elements.len() {
906 return Err(expr);
907 }
908 let Some((drill_expr, drill_ty)) =
912 is_iterator_singleton(expr_elements.iter().zip(in_ty_elements.iter()).filter(
913 |(_expr_elem, in_ty_elem)| find_param_in_ty((*in_ty_elem).into(), param),
914 ))
915 else {
916 return Err(expr);
918 };
919
920 return self.blame_specific_part_of_expr_corresponding_to_generic_param(
921 param,
922 drill_expr,
923 drill_ty.into(),
924 );
925 }
926
927 if let (
928 hir::ExprKind::Struct(expr_struct_path, expr_struct_fields, _expr_struct_rest),
929 ty::Adt(in_ty_adt, in_ty_adt_generic_args),
930 ) = (&expr.kind, in_ty.kind())
931 {
932 let Res::Def(expr_struct_def_kind, expr_struct_def_id) =
935 self.typeck_results.borrow().qpath_res(expr_struct_path, expr.hir_id)
936 else {
937 return Err(expr);
938 };
939
940 let variant_def_id = match expr_struct_def_kind {
941 DefKind::Struct => {
942 if in_ty_adt.did() != expr_struct_def_id {
943 return Err(expr);
945 }
946 expr_struct_def_id
947 }
948 DefKind::Variant => {
949 if in_ty_adt.did() != self.tcx.parent(expr_struct_def_id) {
951 return Err(expr);
953 }
954 expr_struct_def_id
955 }
956 _ => {
957 return Err(expr);
958 }
959 };
960
961 let Some((drill_generic_index, generic_argument_type)) = is_iterator_singleton(
964 in_ty_adt_generic_args
965 .iter()
966 .enumerate()
967 .filter(|(_index, in_ty_generic)| find_param_in_ty(*in_ty_generic, param)),
968 ) else {
969 return Err(expr);
970 };
971
972 let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did());
973 if drill_generic_index >= struct_generic_parameters.own_params.len() {
974 return Err(expr);
975 }
976
977 let param_to_point_at_in_struct = self.tcx.mk_param_from_def(
978 struct_generic_parameters.param_at(drill_generic_index, self.tcx),
979 );
980
981 let (field_expr, field_type) = self
1005 .point_at_field_if_possible(
1006 in_ty_adt.did(),
1007 param_to_point_at_in_struct,
1008 variant_def_id,
1009 expr_struct_fields,
1010 )
1011 .ok_or(expr)?;
1012
1013 let expr = self.blame_specific_part_of_expr_corresponding_to_generic_param(
1016 param_to_point_at_in_struct,
1017 field_expr,
1018 field_type.into(),
1019 )?;
1020
1021 return self.blame_specific_part_of_expr_corresponding_to_generic_param(
1024 param,
1025 expr,
1026 generic_argument_type,
1027 );
1028 }
1029
1030 if let (
1031 hir::ExprKind::Call(expr_callee, expr_args),
1032 ty::Adt(in_ty_adt, in_ty_adt_generic_args),
1033 ) = (&expr.kind, in_ty.kind())
1034 {
1035 let hir::ExprKind::Path(expr_callee_path) = &expr_callee.kind else {
1036 return Err(expr);
1040 };
1041 let Res::Def(expr_struct_def_kind, expr_ctor_def_id) =
1044 self.typeck_results.borrow().qpath_res(expr_callee_path, expr_callee.hir_id)
1045 else {
1046 return Err(expr);
1047 };
1048
1049 let variant_def_id = match expr_struct_def_kind {
1050 DefKind::Ctor(hir::def::CtorOf::Struct, hir::def::CtorKind::Fn) => {
1051 if in_ty_adt.did() != self.tcx.parent(expr_ctor_def_id) {
1052 return Err(expr);
1054 }
1055 self.tcx.parent(expr_ctor_def_id)
1056 }
1057 DefKind::Ctor(hir::def::CtorOf::Variant, hir::def::CtorKind::Fn) => {
1058 if in_ty_adt.did() == self.tcx.parent(self.tcx.parent(expr_ctor_def_id)) {
1071 self.tcx.parent(expr_ctor_def_id)
1074 } else {
1075 return Err(expr);
1077 }
1078 }
1079 _ => {
1080 return Err(expr);
1081 }
1082 };
1083
1084 let Some((drill_generic_index, generic_argument_type)) = is_iterator_singleton(
1087 in_ty_adt_generic_args
1088 .iter()
1089 .enumerate()
1090 .filter(|(_index, in_ty_generic)| find_param_in_ty(*in_ty_generic, param)),
1091 ) else {
1092 return Err(expr);
1093 };
1094
1095 let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did());
1096 if drill_generic_index >= struct_generic_parameters.own_params.len() {
1097 return Err(expr);
1098 }
1099
1100 let param_to_point_at_in_struct = self.tcx.mk_param_from_def(
1101 struct_generic_parameters.param_at(drill_generic_index, self.tcx),
1102 );
1103
1104 let Some((field_index, field_type)) = is_iterator_singleton(
1128 in_ty_adt
1129 .variant_with_id(variant_def_id)
1130 .fields
1131 .iter()
1132 .map(|field| field.ty(self.tcx, in_ty_adt_generic_args).skip_norm_wip())
1133 .enumerate()
1134 .filter(|(_index, field_type)| find_param_in_ty((*field_type).into(), param)),
1135 ) else {
1136 return Err(expr);
1137 };
1138
1139 if field_index >= expr_args.len() {
1140 return Err(expr);
1141 }
1142
1143 let expr = self.blame_specific_part_of_expr_corresponding_to_generic_param(
1146 param_to_point_at_in_struct,
1147 &expr_args[field_index],
1148 field_type.into(),
1149 )?;
1150
1151 return self.blame_specific_part_of_expr_corresponding_to_generic_param(
1154 param,
1155 expr,
1156 generic_argument_type,
1157 );
1158 }
1159
1160 Err(expr)
1166 }
1167}
1168
1169fn find_param_in_ty<'tcx>(
1172 ty: ty::GenericArg<'tcx>,
1173 param_to_point_at: ty::GenericArg<'tcx>,
1174) -> bool {
1175 let mut walk = ty.walk();
1176 while let Some(arg) = walk.next() {
1177 if arg == param_to_point_at {
1178 return true;
1179 }
1180 if let ty::GenericArgKind::Type(ty) = arg.kind()
1181 && let ty::Alias(
1182 _,
1183 ty::AliasTy { kind: ty::Projection { .. } | ty::Inherent { .. }, .. },
1184 ) = ty.kind()
1185 {
1186 walk.skip_current_subtree();
1193 }
1194 }
1195 false
1196}
1197
1198fn is_iterator_singleton<T>(mut iterator: impl Iterator<Item = T>) -> Option<T> {
1200 match (iterator.next(), iterator.next()) {
1201 (_, Some(_)) => None,
1202 (first, _) => first,
1203 }
1204}