rustc_hir_typeck/fn_ctxt/adjust_fulfillment_errors.rs
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 /// Predicate comes from `predicates_of`.
15 Where,
16 /// Predicate comes from `const_conditions`.
17 Const,
18}
19
20#[derive(Copy, Clone, PartialEq, Eq, 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 } else {
62 return false;
63 }
64 }
65 ClauseFlavor::Const => {
66 if let Some((pred, _)) = self
67 .tcx
68 .const_conditions(def_id)
69 .instantiate_identity(self.tcx)
70 .into_iter()
71 .nth(idx)
72 {
73 pred.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe)
74 } else {
75 return false;
76 }
77 }
78 };
79
80 let generics = self.tcx.generics_of(def_id);
81 let (predicate_args, predicate_self_type_to_point_at) =
82 match uninstantiated_pred.kind().skip_binder() {
83 ty::ClauseKind::Trait(pred) => {
84 (pred.trait_ref.args.to_vec(), Some(pred.self_ty().into()))
85 }
86 ty::ClauseKind::HostEffect(pred) => {
87 (pred.trait_ref.args.to_vec(), Some(pred.self_ty().into()))
88 }
89 ty::ClauseKind::Projection(pred) => (pred.projection_term.args.to_vec(), None),
90 ty::ClauseKind::ConstArgHasType(arg, ty) => (vec![ty.into(), arg.into()], None),
91 ty::ClauseKind::ConstEvaluatable(e) => (vec![e.into()], None),
92 _ => return false,
93 };
94
95 let find_param_matching = |matches: &dyn Fn(ParamTerm) -> bool| {
96 predicate_args.iter().find_map(|arg| {
97 arg.walk().find_map(|arg| {
98 if let ty::GenericArgKind::Type(ty) = arg.kind()
99 && let ty::Param(param_ty) = *ty.kind()
100 && matches(ParamTerm::Ty(param_ty))
101 {
102 Some(arg)
103 } else if let ty::GenericArgKind::Const(ct) = arg.kind()
104 && let ty::ConstKind::Param(param_ct) = ct.kind()
105 && matches(ParamTerm::Const(param_ct))
106 {
107 Some(arg)
108 } else {
109 None
110 }
111 })
112 })
113 };
114
115 // Prefer generics that are local to the fn item, since these are likely
116 // to be the cause of the unsatisfied predicate.
117 let mut param_to_point_at = find_param_matching(&|param_term| {
118 self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) == def_id
119 });
120 // Fall back to generic that isn't local to the fn item. This will come
121 // from a trait or impl, for example.
122 let mut fallback_param_to_point_at = find_param_matching(&|param_term| {
123 self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) != def_id
124 && !matches!(param_term, ParamTerm::Ty(ty) if ty.name == kw::SelfUpper)
125 });
126 // Finally, the `Self` parameter is possibly the reason that the predicate
127 // is unsatisfied. This is less likely to be true for methods, because
128 // method probe means that we already kinda check that the predicates due
129 // to the `Self` type are true.
130 let mut self_param_to_point_at = find_param_matching(
131 &|param_term| matches!(param_term, ParamTerm::Ty(ty) if ty.name == kw::SelfUpper),
132 );
133
134 // Finally, for ambiguity-related errors, we actually want to look
135 // for a parameter that is the source of the inference type left
136 // over in this predicate.
137 if let traits::FulfillmentErrorCode::Ambiguity { .. } = error.code {
138 fallback_param_to_point_at = None;
139 self_param_to_point_at = None;
140 param_to_point_at =
141 self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
142 }
143
144 match self.tcx.hir_node(hir_id) {
145 hir::Node::Expr(expr) => self.point_at_expr_if_possible(
146 error,
147 def_id,
148 expr,
149 predicate_self_type_to_point_at,
150 param_to_point_at,
151 fallback_param_to_point_at,
152 self_param_to_point_at,
153 ),
154
155 hir::Node::Ty(hir::Ty { kind: hir::TyKind::Path(qpath), .. }) => {
156 for param in [
157 predicate_self_type_to_point_at,
158 param_to_point_at,
159 fallback_param_to_point_at,
160 self_param_to_point_at,
161 ]
162 .into_iter()
163 .flatten()
164 {
165 if self.point_at_path_if_possible(error, def_id, param, &qpath) {
166 return true;
167 }
168 }
169
170 false
171 }
172
173 _ => false,
174 }
175 }
176
177 fn point_at_expr_if_possible(
178 &self,
179 error: &mut traits::FulfillmentError<'tcx>,
180 callee_def_id: DefId,
181 expr: &'tcx hir::Expr<'tcx>,
182 predicate_self_type_to_point_at: Option<ty::GenericArg<'tcx>>,
183 param_to_point_at: Option<ty::GenericArg<'tcx>>,
184 fallback_param_to_point_at: Option<ty::GenericArg<'tcx>>,
185 self_param_to_point_at: Option<ty::GenericArg<'tcx>>,
186 ) -> bool {
187 if self.closure_span_overlaps_error(error, expr.span) {
188 return false;
189 }
190
191 match expr.kind {
192 hir::ExprKind::Call(
193 hir::Expr { kind: hir::ExprKind::Path(qpath), span: callee_span, .. },
194 args,
195 ) => {
196 if let Some(param) = predicate_self_type_to_point_at
197 && self.point_at_path_if_possible(error, callee_def_id, param, &qpath)
198 {
199 return true;
200 }
201
202 for param in [
203 predicate_self_type_to_point_at,
204 param_to_point_at,
205 fallback_param_to_point_at,
206 self_param_to_point_at,
207 ]
208 .into_iter()
209 .flatten()
210 {
211 if self.blame_specific_arg_if_possible(
212 error,
213 callee_def_id,
214 param,
215 expr.hir_id,
216 *callee_span,
217 None,
218 args,
219 ) {
220 return true;
221 }
222 }
223
224 for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
225 .into_iter()
226 .flatten()
227 {
228 if self.point_at_path_if_possible(error, callee_def_id, param, &qpath) {
229 return true;
230 }
231 }
232 }
233 hir::ExprKind::Path(qpath) => {
234 // If the parent is an call, then process this as a call.
235 //
236 // This is because the `WhereClauseInExpr` obligations come from
237 // the well-formedness of the *path* expression, but we care to
238 // point at the call expression (namely, its args).
239 if let hir::Node::Expr(
240 call_expr @ hir::Expr { kind: hir::ExprKind::Call(callee, ..), .. },
241 ) = self.tcx.parent_hir_node(expr.hir_id)
242 && callee.hir_id == expr.hir_id
243 {
244 return self.point_at_expr_if_possible(
245 error,
246 callee_def_id,
247 call_expr,
248 predicate_self_type_to_point_at,
249 param_to_point_at,
250 fallback_param_to_point_at,
251 self_param_to_point_at,
252 );
253 }
254
255 // Otherwise, just try to point at path components.
256
257 if let Some(param) = predicate_self_type_to_point_at
258 && self.point_at_path_if_possible(error, callee_def_id, param, &qpath)
259 {
260 return true;
261 }
262
263 for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
264 .into_iter()
265 .flatten()
266 {
267 if self.point_at_path_if_possible(error, callee_def_id, param, &qpath) {
268 return true;
269 }
270 }
271 }
272 hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
273 if let Some(param) = predicate_self_type_to_point_at
274 && self.point_at_generic_if_possible(error, callee_def_id, param, segment)
275 {
276 // HACK: This is not correct, since `predicate_self_type_to_point_at` might
277 // not actually correspond to the receiver of the method call. But we
278 // re-adjust the cause code here in order to prefer pointing at one of
279 // the method's turbofish segments but still use `FunctionArgumentObligation`
280 // elsewhere. Hopefully this doesn't break something.
281 error.obligation.cause.map_code(|parent_code| {
282 ObligationCauseCode::FunctionArg {
283 arg_hir_id: receiver.hir_id,
284 call_hir_id: expr.hir_id,
285 parent_code,
286 }
287 });
288 return true;
289 }
290
291 for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
292 .into_iter()
293 .flatten()
294 {
295 if self.blame_specific_arg_if_possible(
296 error,
297 callee_def_id,
298 param,
299 expr.hir_id,
300 segment.ident.span,
301 Some(receiver),
302 args,
303 ) {
304 return true;
305 }
306 }
307 if let Some(param_to_point_at) = param_to_point_at
308 && self.point_at_generic_if_possible(
309 error,
310 callee_def_id,
311 param_to_point_at,
312 segment,
313 )
314 {
315 return true;
316 }
317 // Handle `Self` param specifically, since it's separated in
318 // the method call representation
319 if self_param_to_point_at.is_some() {
320 error.obligation.cause.span = receiver
321 .span
322 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
323 .unwrap_or(receiver.span);
324 return true;
325 }
326 }
327 hir::ExprKind::Struct(qpath, fields, ..) => {
328 if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) =
329 self.typeck_results.borrow().qpath_res(qpath, expr.hir_id)
330 {
331 for param in
332 [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
333 .into_iter()
334 .flatten()
335 {
336 let refined_expr = self.point_at_field_if_possible(
337 callee_def_id,
338 param,
339 variant_def_id,
340 fields,
341 );
342
343 match refined_expr {
344 None => {}
345 Some((refined_expr, _)) => {
346 error.obligation.cause.span = refined_expr
347 .span
348 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
349 .unwrap_or(refined_expr.span);
350 return true;
351 }
352 }
353 }
354 }
355
356 for param in [
357 predicate_self_type_to_point_at,
358 param_to_point_at,
359 fallback_param_to_point_at,
360 self_param_to_point_at,
361 ]
362 .into_iter()
363 .flatten()
364 {
365 if self.point_at_path_if_possible(error, callee_def_id, param, qpath) {
366 return true;
367 }
368 }
369 }
370 _ => {}
371 }
372
373 false
374 }
375
376 fn point_at_path_if_possible(
377 &self,
378 error: &mut traits::FulfillmentError<'tcx>,
379 def_id: DefId,
380 arg: ty::GenericArg<'tcx>,
381 qpath: &hir::QPath<'tcx>,
382 ) -> bool {
383 match qpath {
384 hir::QPath::Resolved(self_ty, path) => {
385 for segment in path.segments.iter().rev() {
386 if let Res::Def(kind, def_id) = segment.res
387 && !matches!(kind, DefKind::Mod | DefKind::ForeignMod)
388 && self.point_at_generic_if_possible(error, def_id, arg, segment)
389 {
390 return true;
391 }
392 }
393 // Handle `Self` param specifically, since it's separated in
394 // the path representation
395 if let Some(self_ty) = self_ty
396 && let ty::GenericArgKind::Type(ty) = arg.kind()
397 && ty == self.tcx.types.self_param
398 {
399 error.obligation.cause.span = self_ty
400 .span
401 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
402 .unwrap_or(self_ty.span);
403 return true;
404 }
405 }
406 hir::QPath::TypeRelative(self_ty, segment) => {
407 if self.point_at_generic_if_possible(error, def_id, arg, segment) {
408 return true;
409 }
410 // Handle `Self` param specifically, since it's separated in
411 // the path representation
412 if let ty::GenericArgKind::Type(ty) = arg.kind()
413 && ty == self.tcx.types.self_param
414 {
415 error.obligation.cause.span = self_ty
416 .span
417 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
418 .unwrap_or(self_ty.span);
419 return true;
420 }
421 }
422 _ => {}
423 }
424
425 false
426 }
427
428 fn point_at_generic_if_possible(
429 &self,
430 error: &mut traits::FulfillmentError<'tcx>,
431 def_id: DefId,
432 param_to_point_at: ty::GenericArg<'tcx>,
433 segment: &hir::PathSegment<'tcx>,
434 ) -> bool {
435 let own_args = self
436 .tcx
437 .generics_of(def_id)
438 .own_args(ty::GenericArgs::identity_for_item(self.tcx, def_id));
439 let Some(mut index) = own_args.iter().position(|arg| *arg == param_to_point_at) else {
440 return false;
441 };
442 // SUBTLE: We may or may not turbofish lifetime arguments, which will
443 // otherwise be elided. if our "own args" starts with a lifetime, but
444 // the args list does not, then we should chop off all of the lifetimes,
445 // since they're all elided.
446 let segment_args = segment.args().args;
447 if matches!(own_args[0].kind(), ty::GenericArgKind::Lifetime(_))
448 && segment_args.first().is_some_and(|arg| arg.is_ty_or_const())
449 && let Some(offset) = own_args.iter().position(|arg| {
450 matches!(arg.kind(), ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_))
451 })
452 && let Some(new_index) = index.checked_sub(offset)
453 {
454 index = new_index;
455 }
456 let Some(arg) = segment_args.get(index) else {
457 return false;
458 };
459 error.obligation.cause.span = arg
460 .span()
461 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
462 .unwrap_or(arg.span());
463 true
464 }
465
466 fn find_ambiguous_parameter_in<T: TypeVisitable<TyCtxt<'tcx>>>(
467 &self,
468 item_def_id: DefId,
469 t: T,
470 ) -> Option<ty::GenericArg<'tcx>> {
471 struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId);
472 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindAmbiguousParameter<'_, 'tcx> {
473 type Result = ControlFlow<ty::GenericArg<'tcx>>;
474 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
475 if let ty::Infer(ty::TyVar(vid)) = *ty.kind()
476 && let Some(def_id) = self.0.type_var_origin(vid).param_def_id
477 && let generics = self.0.tcx.generics_of(self.1)
478 && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
479 && let Some(arg) =
480 ty::GenericArgs::identity_for_item(self.0.tcx, self.1).get(index as usize)
481 {
482 ControlFlow::Break(*arg)
483 } else {
484 ty.super_visit_with(self)
485 }
486 }
487 }
488 t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value()
489 }
490
491 fn closure_span_overlaps_error(
492 &self,
493 error: &traits::FulfillmentError<'tcx>,
494 span: Span,
495 ) -> bool {
496 if let traits::FulfillmentErrorCode::Select(traits::SelectionError::SignatureMismatch(
497 box traits::SignatureMismatchData { expected_trait_ref, .. },
498 )) = error.code
499 && let ty::Closure(def_id, _) | ty::Coroutine(def_id, ..) =
500 expected_trait_ref.self_ty().kind()
501 && span.overlaps(self.tcx.def_span(*def_id))
502 {
503 true
504 } else {
505 false
506 }
507 }
508
509 fn point_at_field_if_possible(
510 &self,
511 def_id: DefId,
512 param_to_point_at: ty::GenericArg<'tcx>,
513 variant_def_id: DefId,
514 expr_fields: &[hir::ExprField<'tcx>],
515 ) -> Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)> {
516 let def = self.tcx.adt_def(def_id);
517
518 let identity_args = ty::GenericArgs::identity_for_item(self.tcx, def_id);
519 let fields_referencing_param: Vec<_> = def
520 .variant_with_id(variant_def_id)
521 .fields
522 .iter()
523 .filter(|field| {
524 let field_ty = field.ty(self.tcx, identity_args);
525 find_param_in_ty(field_ty.into(), param_to_point_at)
526 })
527 .collect();
528
529 if let [field] = fields_referencing_param.as_slice() {
530 for expr_field in expr_fields {
531 // Look for the ExprField that matches the field, using the
532 // same rules that check_expr_struct uses for macro hygiene.
533 if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx)
534 {
535 return Some((
536 expr_field.expr,
537 self.tcx.type_of(field.did).instantiate_identity(),
538 ));
539 }
540 }
541 }
542
543 None
544 }
545
546 /// - `blame_specific_*` means that the function will recursively traverse the expression,
547 /// looking for the most-specific-possible span to blame.
548 ///
549 /// - `point_at_*` means that the function will only go "one level", pointing at the specific
550 /// expression mentioned.
551 ///
552 /// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside
553 /// the provided function call expression, and mark it as responsible for the fulfillment
554 /// error.
555 fn blame_specific_arg_if_possible(
556 &self,
557 error: &mut traits::FulfillmentError<'tcx>,
558 def_id: DefId,
559 param_to_point_at: ty::GenericArg<'tcx>,
560 call_hir_id: hir::HirId,
561 callee_span: Span,
562 receiver: Option<&'tcx hir::Expr<'tcx>>,
563 args: &'tcx [hir::Expr<'tcx>],
564 ) -> bool {
565 let ty = self.tcx.type_of(def_id).instantiate_identity();
566 if !ty.is_fn() {
567 return false;
568 }
569 let sig = ty.fn_sig(self.tcx).skip_binder();
570 let args_referencing_param: Vec<_> = sig
571 .inputs()
572 .iter()
573 .enumerate()
574 .filter(|(_, ty)| find_param_in_ty((**ty).into(), param_to_point_at))
575 .collect();
576 // If there's one field that references the given generic, great!
577 if let [(idx, _)] = args_referencing_param.as_slice()
578 && let Some(arg) = receiver.map_or(args.get(*idx), |rcvr| {
579 if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }
580 })
581 {
582 error.obligation.cause.span = arg
583 .span
584 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
585 .unwrap_or(arg.span);
586
587 if let hir::Node::Expr(arg_expr) = self.tcx.hir_node(arg.hir_id) {
588 // This is more specific than pointing at the entire argument.
589 self.blame_specific_expr_if_possible(error, arg_expr)
590 }
591
592 error.obligation.cause.map_code(|parent_code| ObligationCauseCode::FunctionArg {
593 arg_hir_id: arg.hir_id,
594 call_hir_id,
595 parent_code,
596 });
597 return true;
598 } else if args_referencing_param.len() > 0 {
599 // If more than one argument applies, then point to the callee span at least...
600 // We have chance to fix this up further in `point_at_generics_if_possible`
601 error.obligation.cause.span = callee_span;
602 }
603
604 false
605 }
606
607 /**
608 * Recursively searches for the most-specific blameable expression.
609 * For example, if you have a chain of constraints like:
610 * - want `Vec<i32>: Copy`
611 * - because `Option<Vec<i32>>: Copy` needs `Vec<i32>: Copy` because `impl <T: Copy> Copy for Option<T>`
612 * - because `(Option<Vec<i32>, bool)` needs `Option<Vec<i32>>: Copy` because `impl <A: Copy, B: Copy> Copy for (A, B)`
613 * then if you pass in `(Some(vec![1, 2, 3]), false)`, this helper `point_at_specific_expr_if_possible`
614 * will find the expression `vec![1, 2, 3]` as the "most blameable" reason for this missing constraint.
615 *
616 * This function only updates the error span.
617 */
618 pub(crate) fn blame_specific_expr_if_possible(
619 &self,
620 error: &mut traits::FulfillmentError<'tcx>,
621 expr: &'tcx hir::Expr<'tcx>,
622 ) {
623 // Whether it succeeded or failed, it likely made some amount of progress.
624 // In the very worst case, it's just the same `expr` we originally passed in.
625 let expr = match self.blame_specific_expr_if_possible_for_obligation_cause_code(
626 error.obligation.cause.code(),
627 expr,
628 ) {
629 Ok(expr) => expr,
630 Err(expr) => expr,
631 };
632
633 // Either way, use this expression to update the error span.
634 // If it doesn't overlap the existing span at all, use the original span.
635 // FIXME: It would possibly be better to do this more continuously, at each level...
636 error.obligation.cause.span = expr
637 .span
638 .find_ancestor_in_same_ctxt(error.obligation.cause.span)
639 .unwrap_or(error.obligation.cause.span);
640 }
641
642 fn blame_specific_expr_if_possible_for_obligation_cause_code(
643 &self,
644 obligation_cause_code: &traits::ObligationCauseCode<'tcx>,
645 expr: &'tcx hir::Expr<'tcx>,
646 ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
647 match obligation_cause_code {
648 traits::ObligationCauseCode::WhereClauseInExpr(_, _, _, _)
649 | ObligationCauseCode::HostEffectInExpr(..) => {
650 // This is the "root"; we assume that the `expr` is already pointing here.
651 // Therefore, we return `Ok` so that this `expr` can be refined further.
652 Ok(expr)
653 }
654 traits::ObligationCauseCode::ImplDerived(impl_derived) => self
655 .blame_specific_expr_if_possible_for_derived_predicate_obligation(
656 impl_derived,
657 expr,
658 ),
659 _ => {
660 // We don't recognize this kind of constraint, so we cannot refine the expression
661 // any further.
662 Err(expr)
663 }
664 }
665 }
666
667 /// We want to achieve the error span in the following example:
668 ///
669 /// ```ignore (just for demonstration)
670 /// struct Burrito<Filling> {
671 /// filling: Filling,
672 /// }
673 /// impl <Filling: Delicious> Delicious for Burrito<Filling> {}
674 /// fn eat_delicious_food<Food: Delicious>(_food: Food) {}
675 ///
676 /// fn will_type_error() {
677 /// eat_delicious_food(Burrito { filling: Kale });
678 /// } // ^--- The trait bound `Kale: Delicious`
679 /// // is not satisfied
680 /// ```
681 ///
682 /// Without calling this function, the error span will cover the entire argument expression.
683 ///
684 /// Before we do any of this logic, we recursively call `point_at_specific_expr_if_possible` on the parent
685 /// obligation. Hence we refine the `expr` "outwards-in" and bail at the first kind of expression/impl we don't recognize.
686 ///
687 /// This function returns a `Result<&Expr, &Expr>` - either way, it returns the `Expr` whose span should be
688 /// reported as an error. If it is `Ok`, then it means it refined successful. If it is `Err`, then it may be
689 /// only a partial success - but it cannot be refined even further.
690 fn blame_specific_expr_if_possible_for_derived_predicate_obligation(
691 &self,
692 obligation: &traits::ImplDerivedCause<'tcx>,
693 expr: &'tcx hir::Expr<'tcx>,
694 ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
695 // First, we attempt to refine the `expr` for our span using the parent obligation.
696 // If this cannot be done, then we are already stuck, so we stop early (hence the use
697 // of the `?` try operator here).
698 let expr = self.blame_specific_expr_if_possible_for_obligation_cause_code(
699 &*obligation.derived.parent_code,
700 expr,
701 )?;
702
703 // This is the "trait" (meaning, the predicate "proved" by this `impl`) which provides the `Self` type we care about.
704 // For the purposes of this function, we hope that it is a `struct` type, and that our current `expr` is a literal of
705 // that struct type.
706 let impl_trait_self_ref = if self.tcx.is_trait_alias(obligation.impl_or_alias_def_id) {
707 ty::TraitRef::new_from_args(
708 self.tcx,
709 obligation.impl_or_alias_def_id,
710 ty::GenericArgs::identity_for_item(self.tcx, obligation.impl_or_alias_def_id),
711 )
712 } else {
713 self.tcx
714 .impl_trait_ref(obligation.impl_or_alias_def_id)
715 .map(|impl_def| impl_def.skip_binder())
716 // It is possible that this is absent. In this case, we make no progress.
717 .ok_or(expr)?
718 };
719
720 // We only really care about the `Self` type itself, which we extract from the ref.
721 let impl_self_ty: Ty<'tcx> = impl_trait_self_ref.self_ty();
722
723 let impl_predicates: ty::GenericPredicates<'tcx> =
724 self.tcx.predicates_of(obligation.impl_or_alias_def_id);
725 let Some(impl_predicate_index) = obligation.impl_def_predicate_index else {
726 // We don't have the index, so we can only guess.
727 return Err(expr);
728 };
729
730 if impl_predicate_index >= impl_predicates.predicates.len() {
731 // This shouldn't happen, but since this is only a diagnostic improvement, avoid breaking things.
732 return Err(expr);
733 }
734
735 match impl_predicates.predicates[impl_predicate_index].0.kind().skip_binder() {
736 ty::ClauseKind::Trait(broken_trait) => {
737 // ...
738 self.blame_specific_part_of_expr_corresponding_to_generic_param(
739 broken_trait.trait_ref.self_ty().into(),
740 expr,
741 impl_self_ty.into(),
742 )
743 }
744 _ => Err(expr),
745 }
746 }
747
748 /// Drills into `expr` to arrive at the equivalent location of `find_generic_param` in `in_ty`.
749 /// For example, given
750 /// - expr: `(Some(vec![1, 2, 3]), false)`
751 /// - param: `T`
752 /// - in_ty: `(Option<Vec<T>, bool)`
753 /// we would drill until we arrive at `vec![1, 2, 3]`.
754 ///
755 /// If successful, we return `Ok(refined_expr)`. If unsuccessful, we return `Err(partially_refined_expr`),
756 /// which will go as far as possible. For example, given `(foo(), false)` instead, we would drill to
757 /// `foo()` and then return `Err("foo()")`.
758 ///
759 /// This means that you can (and should) use the `?` try operator to chain multiple calls to this
760 /// function with different types, since you can only continue drilling the second time if you
761 /// succeeded the first time.
762 fn blame_specific_part_of_expr_corresponding_to_generic_param(
763 &self,
764 param: ty::GenericArg<'tcx>,
765 expr: &'tcx hir::Expr<'tcx>,
766 in_ty: ty::GenericArg<'tcx>,
767 ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
768 if param == in_ty {
769 // The types match exactly, so we have drilled as far as we can.
770 return Ok(expr);
771 }
772
773 let ty::GenericArgKind::Type(in_ty) = in_ty.kind() else {
774 return Err(expr);
775 };
776
777 if let (
778 hir::ExprKind::AddrOf(_borrow_kind, _borrow_mutability, borrowed_expr),
779 ty::Ref(_ty_region, ty_ref_type, _ty_mutability),
780 ) = (&expr.kind, in_ty.kind())
781 {
782 // We can "drill into" the borrowed expression.
783 return self.blame_specific_part_of_expr_corresponding_to_generic_param(
784 param,
785 borrowed_expr,
786 (*ty_ref_type).into(),
787 );
788 }
789
790 if let (hir::ExprKind::Tup(expr_elements), ty::Tuple(in_ty_elements)) =
791 (&expr.kind, in_ty.kind())
792 {
793 if in_ty_elements.len() != expr_elements.len() {
794 return Err(expr);
795 }
796 // Find out which of `in_ty_elements` refer to `param`.
797 // FIXME: It may be better to take the first if there are multiple,
798 // just so that the error points to a smaller expression.
799 let Some((drill_expr, drill_ty)) =
800 is_iterator_singleton(expr_elements.iter().zip(in_ty_elements.iter()).filter(
801 |(_expr_elem, in_ty_elem)| find_param_in_ty((*in_ty_elem).into(), param),
802 ))
803 else {
804 // The param is not mentioned, or it is mentioned in multiple indexes.
805 return Err(expr);
806 };
807
808 return self.blame_specific_part_of_expr_corresponding_to_generic_param(
809 param,
810 drill_expr,
811 drill_ty.into(),
812 );
813 }
814
815 if let (
816 hir::ExprKind::Struct(expr_struct_path, expr_struct_fields, _expr_struct_rest),
817 ty::Adt(in_ty_adt, in_ty_adt_generic_args),
818 ) = (&expr.kind, in_ty.kind())
819 {
820 // First, confirm that this struct is the same one as in the types, and if so,
821 // find the right variant.
822 let Res::Def(expr_struct_def_kind, expr_struct_def_id) =
823 self.typeck_results.borrow().qpath_res(expr_struct_path, expr.hir_id)
824 else {
825 return Err(expr);
826 };
827
828 let variant_def_id = match expr_struct_def_kind {
829 DefKind::Struct => {
830 if in_ty_adt.did() != expr_struct_def_id {
831 // FIXME: Deal with type aliases?
832 return Err(expr);
833 }
834 expr_struct_def_id
835 }
836 DefKind::Variant => {
837 // If this is a variant, its parent is the type definition.
838 if in_ty_adt.did() != self.tcx.parent(expr_struct_def_id) {
839 // FIXME: Deal with type aliases?
840 return Err(expr);
841 }
842 expr_struct_def_id
843 }
844 _ => {
845 return Err(expr);
846 }
847 };
848
849 // We need to know which of the generic parameters mentions our target param.
850 // We expect that at least one of them does, since it is expected to be mentioned.
851 let Some((drill_generic_index, generic_argument_type)) = is_iterator_singleton(
852 in_ty_adt_generic_args
853 .iter()
854 .enumerate()
855 .filter(|(_index, in_ty_generic)| find_param_in_ty(*in_ty_generic, param)),
856 ) else {
857 return Err(expr);
858 };
859
860 let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did());
861 if drill_generic_index >= struct_generic_parameters.own_params.len() {
862 return Err(expr);
863 }
864
865 let param_to_point_at_in_struct = self.tcx.mk_param_from_def(
866 struct_generic_parameters.param_at(drill_generic_index, self.tcx),
867 );
868
869 // We make 3 steps:
870 // Suppose we have a type like
871 // ```ignore (just for demonstration)
872 // struct ExampleStruct<T> {
873 // enabled: bool,
874 // item: Option<(usize, T, bool)>,
875 // }
876 //
877 // f(ExampleStruct {
878 // enabled: false,
879 // item: Some((0, Box::new(String::new()), 1) }, true)),
880 // });
881 // ```
882 // Here, `f` is passed a `ExampleStruct<Box<String>>`, but it wants
883 // for `String: Copy`, which isn't true here.
884 //
885 // (1) First, we drill into `.item` and highlight that expression
886 // (2) Then we use the template type `Option<(usize, T, bool)>` to
887 // drill into the `T`, arriving at a `Box<String>` expression.
888 // (3) Then we keep going, drilling into this expression using our
889 // outer contextual information.
890
891 // (1) Find the (unique) field which mentions the type in our constraint:
892 let (field_expr, field_type) = self
893 .point_at_field_if_possible(
894 in_ty_adt.did(),
895 param_to_point_at_in_struct,
896 variant_def_id,
897 expr_struct_fields,
898 )
899 .ok_or(expr)?;
900
901 // (2) Continue drilling into the struct, ignoring the struct's
902 // generic argument types.
903 let expr = self.blame_specific_part_of_expr_corresponding_to_generic_param(
904 param_to_point_at_in_struct,
905 field_expr,
906 field_type.into(),
907 )?;
908
909 // (3) Continue drilling into the expression, having "passed
910 // through" the struct entirely.
911 return self.blame_specific_part_of_expr_corresponding_to_generic_param(
912 param,
913 expr,
914 generic_argument_type,
915 );
916 }
917
918 if let (
919 hir::ExprKind::Call(expr_callee, expr_args),
920 ty::Adt(in_ty_adt, in_ty_adt_generic_args),
921 ) = (&expr.kind, in_ty.kind())
922 {
923 let hir::ExprKind::Path(expr_callee_path) = &expr_callee.kind else {
924 // FIXME: This case overlaps with another one worth handling,
925 // which should happen above since it applies to non-ADTs:
926 // we can drill down into regular generic functions.
927 return Err(expr);
928 };
929 // This is (possibly) a constructor call, like `Some(...)` or `MyStruct(a, b, c)`.
930
931 let Res::Def(expr_struct_def_kind, expr_ctor_def_id) =
932 self.typeck_results.borrow().qpath_res(expr_callee_path, expr_callee.hir_id)
933 else {
934 return Err(expr);
935 };
936
937 let variant_def_id = match expr_struct_def_kind {
938 DefKind::Ctor(hir::def::CtorOf::Struct, hir::def::CtorKind::Fn) => {
939 if in_ty_adt.did() != self.tcx.parent(expr_ctor_def_id) {
940 // FIXME: Deal with type aliases?
941 return Err(expr);
942 }
943 self.tcx.parent(expr_ctor_def_id)
944 }
945 DefKind::Ctor(hir::def::CtorOf::Variant, hir::def::CtorKind::Fn) => {
946 // For a typical enum like
947 // `enum Blah<T> { Variant(T) }`
948 // we get the following resolutions:
949 // - expr_ctor_def_id ::: DefId(0:29 ~ source_file[b442]::Blah::Variant::{constructor#0})
950 // - self.tcx.parent(expr_ctor_def_id) ::: DefId(0:28 ~ source_file[b442]::Blah::Variant)
951 // - self.tcx.parent(self.tcx.parent(expr_ctor_def_id)) ::: DefId(0:26 ~ source_file[b442]::Blah)
952
953 // Therefore, we need to go up once to obtain the variant and up twice to obtain the type.
954 // Note that this pattern still holds even when we `use` a variant or `use` an enum type to rename it, or chain `use` expressions
955 // together; this resolution is handled automatically by `qpath_res`.
956
957 // FIXME: Deal with type aliases?
958 if in_ty_adt.did() == self.tcx.parent(self.tcx.parent(expr_ctor_def_id)) {
959 // The constructor definition refers to the "constructor" of the variant:
960 // For example, `Some(5)` triggers this case.
961 self.tcx.parent(expr_ctor_def_id)
962 } else {
963 // FIXME: Deal with type aliases?
964 return Err(expr);
965 }
966 }
967 _ => {
968 return Err(expr);
969 }
970 };
971
972 // We need to know which of the generic parameters mentions our target param.
973 // We expect that at least one of them does, since it is expected to be mentioned.
974 let Some((drill_generic_index, generic_argument_type)) = is_iterator_singleton(
975 in_ty_adt_generic_args
976 .iter()
977 .enumerate()
978 .filter(|(_index, in_ty_generic)| find_param_in_ty(*in_ty_generic, param)),
979 ) else {
980 return Err(expr);
981 };
982
983 let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did());
984 if drill_generic_index >= struct_generic_parameters.own_params.len() {
985 return Err(expr);
986 }
987
988 let param_to_point_at_in_struct = self.tcx.mk_param_from_def(
989 struct_generic_parameters.param_at(drill_generic_index, self.tcx),
990 );
991
992 // We make 3 steps:
993 // Suppose we have a type like
994 // ```ignore (just for demonstration)
995 // struct ExampleStruct<T> {
996 // enabled: bool,
997 // item: Option<(usize, T, bool)>,
998 // }
999 //
1000 // f(ExampleStruct {
1001 // enabled: false,
1002 // item: Some((0, Box::new(String::new()), 1) }, true)),
1003 // });
1004 // ```
1005 // Here, `f` is passed a `ExampleStruct<Box<String>>`, but it wants
1006 // for `String: Copy`, which isn't true here.
1007 //
1008 // (1) First, we drill into `.item` and highlight that expression
1009 // (2) Then we use the template type `Option<(usize, T, bool)>` to
1010 // drill into the `T`, arriving at a `Box<String>` expression.
1011 // (3) Then we keep going, drilling into this expression using our
1012 // outer contextual information.
1013
1014 // (1) Find the (unique) field index which mentions the type in our constraint:
1015 let Some((field_index, field_type)) = is_iterator_singleton(
1016 in_ty_adt
1017 .variant_with_id(variant_def_id)
1018 .fields
1019 .iter()
1020 .map(|field| field.ty(self.tcx, *in_ty_adt_generic_args))
1021 .enumerate()
1022 .filter(|(_index, field_type)| find_param_in_ty((*field_type).into(), param)),
1023 ) else {
1024 return Err(expr);
1025 };
1026
1027 if field_index >= expr_args.len() {
1028 return Err(expr);
1029 }
1030
1031 // (2) Continue drilling into the struct, ignoring the struct's
1032 // generic argument types.
1033 let expr = self.blame_specific_part_of_expr_corresponding_to_generic_param(
1034 param_to_point_at_in_struct,
1035 &expr_args[field_index],
1036 field_type.into(),
1037 )?;
1038
1039 // (3) Continue drilling into the expression, having "passed
1040 // through" the struct entirely.
1041 return self.blame_specific_part_of_expr_corresponding_to_generic_param(
1042 param,
1043 expr,
1044 generic_argument_type,
1045 );
1046 }
1047
1048 // At this point, none of the basic patterns matched.
1049 // One major possibility which remains is that we have a function call.
1050 // In this case, it's often possible to dive deeper into the call to find something to blame,
1051 // but this is not always possible.
1052
1053 Err(expr)
1054 }
1055}
1056
1057/// Traverses the given ty (either a `ty::Ty` or a `ty::GenericArg`) and searches for references
1058/// to the given `param_to_point_at`. Returns `true` if it finds any use of the param.
1059fn find_param_in_ty<'tcx>(
1060 ty: ty::GenericArg<'tcx>,
1061 param_to_point_at: ty::GenericArg<'tcx>,
1062) -> bool {
1063 let mut walk = ty.walk();
1064 while let Some(arg) = walk.next() {
1065 if arg == param_to_point_at {
1066 return true;
1067 }
1068 if let ty::GenericArgKind::Type(ty) = arg.kind()
1069 && let ty::Alias(ty::Projection | ty::Inherent, ..) = ty.kind()
1070 {
1071 // This logic may seem a bit strange, but typically when
1072 // we have a projection type in a function signature, the
1073 // argument that's being passed into that signature is
1074 // not actually constraining that projection's args in
1075 // a meaningful way. So we skip it, and see improvements
1076 // in some UI tests.
1077 walk.skip_current_subtree();
1078 }
1079 }
1080 false
1081}
1082
1083/// Returns `Some(iterator.next())` if it has exactly one item, and `None` otherwise.
1084fn is_iterator_singleton<T>(mut iterator: impl Iterator<Item = T>) -> Option<T> {
1085 match (iterator.next(), iterator.next()) {
1086 (_, Some(_)) => None,
1087 (first, _) => first,
1088 }
1089}