1use std::assert_matches::debug_assert_matches;
4use std::borrow::Cow;
5use std::iter;
6use std::path::PathBuf;
7
8use itertools::{EitherOrBoth, Itertools};
9use rustc_abi::ExternAbi;
10use rustc_data_structures::fx::FxHashSet;
11use rustc_data_structures::stack::ensure_sufficient_stack;
12use rustc_errors::codes::*;
13use rustc_errors::{
14 Applicability, Diag, EmissionGuarantee, MultiSpan, Style, SuggestionStyle, pluralize,
15 struct_span_code_err,
16};
17use rustc_hir::def::{CtorOf, DefKind, Res};
18use rustc_hir::def_id::DefId;
19use rustc_hir::intravisit::{Visitor, VisitorExt};
20use rustc_hir::lang_items::LangItem;
21use rustc_hir::{
22 self as hir, AmbigArg, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node,
23 expr_needs_parens, is_range_literal,
24};
25use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk};
26use rustc_middle::middle::privacy::Level;
27use rustc_middle::traits::IsConstable;
28use rustc_middle::ty::error::TypeError;
29use rustc_middle::ty::print::{
30 PrintPolyTraitPredicateExt as _, PrintPolyTraitRefExt, PrintTraitPredicateExt as _,
31 with_forced_trimmed_paths, with_no_trimmed_paths, with_types_for_suggestion,
32};
33use rustc_middle::ty::{
34 self, AdtKind, GenericArgs, InferTy, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeFolder,
35 TypeSuperFoldable, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, TypeckResults, Upcast,
36 suggest_arbitrary_trait_bound, suggest_constraining_type_param,
37};
38use rustc_middle::{bug, span_bug};
39use rustc_span::def_id::LocalDefId;
40use rustc_span::{
41 BytePos, DUMMY_SP, DesugaringKind, ExpnKind, Ident, MacroKind, Span, Symbol, kw, sym,
42};
43use tracing::{debug, instrument};
44
45use super::{
46 DefIdOrName, FindExprBySpan, ImplCandidate, Obligation, ObligationCause, ObligationCauseCode,
47 PredicateObligation,
48};
49use crate::error_reporting::TypeErrCtxt;
50use crate::errors;
51use crate::infer::InferCtxtExt as _;
52use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
53use crate::traits::{ImplDerivedCause, NormalizeExt, ObligationCtxt};
54
55#[derive(Debug)]
56pub enum CoroutineInteriorOrUpvar {
57 Interior(Span, Option<(Span, Option<Span>)>),
59 Upvar(Span),
61}
62
63#[derive(Debug)]
66struct CoroutineData<'a, 'tcx>(&'a TypeckResults<'tcx>);
67
68impl<'a, 'tcx> CoroutineData<'a, 'tcx> {
69 fn try_get_upvar_span<F>(
73 &self,
74 infer_context: &InferCtxt<'tcx>,
75 coroutine_did: DefId,
76 ty_matches: F,
77 ) -> Option<CoroutineInteriorOrUpvar>
78 where
79 F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,
80 {
81 infer_context.tcx.upvars_mentioned(coroutine_did).and_then(|upvars| {
82 upvars.iter().find_map(|(upvar_id, upvar)| {
83 let upvar_ty = self.0.node_type(*upvar_id);
84 let upvar_ty = infer_context.resolve_vars_if_possible(upvar_ty);
85 ty_matches(ty::Binder::dummy(upvar_ty))
86 .then(|| CoroutineInteriorOrUpvar::Upvar(upvar.span))
87 })
88 })
89 }
90
91 fn get_from_await_ty<F>(
95 &self,
96 visitor: AwaitsVisitor,
97 tcx: TyCtxt<'tcx>,
98 ty_matches: F,
99 ) -> Option<Span>
100 where
101 F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,
102 {
103 visitor
104 .awaits
105 .into_iter()
106 .map(|id| tcx.hir_expect_expr(id))
107 .find(|await_expr| ty_matches(ty::Binder::dummy(self.0.expr_ty_adjusted(await_expr))))
108 .map(|expr| expr.span)
109 }
110}
111
112fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) {
113 (
114 generics.tail_span_for_predicate_suggestion(),
115 with_types_for_suggestion!(format!("{} {}", generics.add_where_or_trailing_comma(), pred)),
116 )
117}
118
119pub fn suggest_restriction<'tcx, G: EmissionGuarantee>(
123 tcx: TyCtxt<'tcx>,
124 item_id: LocalDefId,
125 hir_generics: &hir::Generics<'tcx>,
126 msg: &str,
127 err: &mut Diag<'_, G>,
128 fn_sig: Option<&hir::FnSig<'_>>,
129 projection: Option<ty::AliasTy<'_>>,
130 trait_pred: ty::PolyTraitPredicate<'tcx>,
131 super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>,
137) {
138 if hir_generics.where_clause_span.from_expansion()
139 || hir_generics.where_clause_span.desugaring_kind().is_some()
140 || projection.is_some_and(|projection| {
141 (tcx.is_impl_trait_in_trait(projection.def_id)
142 && !tcx.features().return_type_notation())
143 || tcx.lookup_stability(projection.def_id).is_some_and(|stab| stab.is_unstable())
144 })
145 {
146 return;
147 }
148 let generics = tcx.generics_of(item_id);
149 if let Some((param, bound_str, fn_sig)) =
151 fn_sig.zip(projection).and_then(|(sig, p)| match *p.self_ty().kind() {
152 ty::Param(param) => {
154 let param_def = generics.type_param(param, tcx);
155 if param_def.kind.is_synthetic() {
156 let bound_str =
157 param_def.name.as_str().strip_prefix("impl ")?.trim_start().to_string();
158 return Some((param_def, bound_str, sig));
159 }
160 None
161 }
162 _ => None,
163 })
164 {
165 let type_param_name = hir_generics.params.next_type_param_name(Some(&bound_str));
166 let trait_pred = trait_pred.fold_with(&mut ReplaceImplTraitFolder {
167 tcx,
168 param,
169 replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name))
170 .to_ty(tcx),
171 });
172 if !trait_pred.is_suggestable(tcx, false) {
173 return;
174 }
175 let mut ty_spans = vec![];
183 for input in fn_sig.decl.inputs {
184 ReplaceImplTraitVisitor { ty_spans: &mut ty_spans, param_did: param.def_id }
185 .visit_ty_unambig(input);
186 }
187 let type_param = format!("{type_param_name}: {bound_str}");
189
190 let mut sugg = vec![
191 if let Some(span) = hir_generics.span_for_param_suggestion() {
192 (span, format!(", {type_param}"))
193 } else {
194 (hir_generics.span, format!("<{type_param}>"))
195 },
196 predicate_constraint(hir_generics, trait_pred.upcast(tcx)),
199 ];
200 sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string())));
201
202 err.multipart_suggestion(
205 "introduce a type parameter with a trait bound instead of using `impl Trait`",
206 sugg,
207 Applicability::MaybeIncorrect,
208 );
209 } else {
210 if !trait_pred.is_suggestable(tcx, false) {
211 return;
212 }
213 let (sp, suggestion) = match (
215 hir_generics
216 .params
217 .iter()
218 .find(|p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: true, .. })),
219 super_traits,
220 ) {
221 (_, None) => predicate_constraint(hir_generics, trait_pred.upcast(tcx)),
222 (None, Some((ident, []))) => (
223 ident.span.shrink_to_hi(),
224 format!(": {}", trait_pred.print_modifiers_and_trait_path()),
225 ),
226 (_, Some((_, [.., bounds]))) => (
227 bounds.span().shrink_to_hi(),
228 format!(" + {}", trait_pred.print_modifiers_and_trait_path()),
229 ),
230 (Some(_), Some((_, []))) => (
231 hir_generics.span.shrink_to_hi(),
232 format!(": {}", trait_pred.print_modifiers_and_trait_path()),
233 ),
234 };
235
236 err.span_suggestion_verbose(
237 sp,
238 format!("consider further restricting {msg}"),
239 suggestion,
240 Applicability::MachineApplicable,
241 );
242 }
243}
244
245impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
246 pub fn suggest_restricting_param_bound(
247 &self,
248 err: &mut Diag<'_>,
249 trait_pred: ty::PolyTraitPredicate<'tcx>,
250 associated_ty: Option<(&'static str, Ty<'tcx>)>,
251 mut body_id: LocalDefId,
252 ) {
253 if trait_pred.skip_binder().polarity != ty::PredicatePolarity::Positive {
254 return;
255 }
256
257 let trait_pred = self.resolve_numeric_literals_with_default(trait_pred);
258
259 let self_ty = trait_pred.skip_binder().self_ty();
260 let (param_ty, projection) = match *self_ty.kind() {
261 ty::Param(_) => (true, None),
262 ty::Alias(ty::Projection, projection) => (false, Some(projection)),
263 _ => (false, None),
264 };
265
266 let mut finder = ParamFinder { .. };
267 finder.visit_binder(&trait_pred);
268
269 loop {
272 let node = self.tcx.hir_node_by_def_id(body_id);
273 match node {
274 hir::Node::Item(hir::Item {
275 kind: hir::ItemKind::Trait(_, _, _, ident, generics, bounds, _),
276 ..
277 }) if self_ty == self.tcx.types.self_param => {
278 assert!(param_ty);
279 suggest_restriction(
281 self.tcx,
282 body_id,
283 generics,
284 "`Self`",
285 err,
286 None,
287 projection,
288 trait_pred,
289 Some((&ident, bounds)),
290 );
291 return;
292 }
293
294 hir::Node::TraitItem(hir::TraitItem {
295 generics,
296 kind: hir::TraitItemKind::Fn(..),
297 ..
298 }) if self_ty == self.tcx.types.self_param => {
299 assert!(param_ty);
300 suggest_restriction(
302 self.tcx, body_id, generics, "`Self`", err, None, projection, trait_pred,
303 None,
304 );
305 return;
306 }
307
308 hir::Node::TraitItem(hir::TraitItem {
309 generics,
310 kind: hir::TraitItemKind::Fn(fn_sig, ..),
311 ..
312 })
313 | hir::Node::ImplItem(hir::ImplItem {
314 generics,
315 kind: hir::ImplItemKind::Fn(fn_sig, ..),
316 ..
317 })
318 | hir::Node::Item(hir::Item {
319 kind: hir::ItemKind::Fn { sig: fn_sig, generics, .. },
320 ..
321 }) if projection.is_some() => {
322 suggest_restriction(
324 self.tcx,
325 body_id,
326 generics,
327 "the associated type",
328 err,
329 Some(fn_sig),
330 projection,
331 trait_pred,
332 None,
333 );
334 return;
335 }
336 hir::Node::Item(hir::Item {
337 kind:
338 hir::ItemKind::Trait(_, _, _, _, generics, ..)
339 | hir::ItemKind::Impl(hir::Impl { generics, .. }),
340 ..
341 }) if projection.is_some() => {
342 suggest_restriction(
344 self.tcx,
345 body_id,
346 generics,
347 "the associated type",
348 err,
349 None,
350 projection,
351 trait_pred,
352 None,
353 );
354 return;
355 }
356
357 hir::Node::Item(hir::Item {
358 kind:
359 hir::ItemKind::Struct(_, generics, _)
360 | hir::ItemKind::Enum(_, generics, _)
361 | hir::ItemKind::Union(_, generics, _)
362 | hir::ItemKind::Trait(_, _, _, _, generics, ..)
363 | hir::ItemKind::Impl(hir::Impl { generics, .. })
364 | hir::ItemKind::Fn { generics, .. }
365 | hir::ItemKind::TyAlias(_, generics, _)
366 | hir::ItemKind::Const(_, generics, _, _)
367 | hir::ItemKind::TraitAlias(_, generics, _),
368 ..
369 })
370 | hir::Node::TraitItem(hir::TraitItem { generics, .. })
371 | hir::Node::ImplItem(hir::ImplItem { generics, .. })
372 if param_ty =>
373 {
374 if !trait_pred.skip_binder().trait_ref.args[1..]
383 .iter()
384 .all(|g| g.is_suggestable(self.tcx, false))
385 {
386 return;
387 }
388 let param_name = self_ty.to_string();
390 let mut constraint = with_no_trimmed_paths!(
391 trait_pred.print_modifiers_and_trait_path().to_string()
392 );
393
394 if let Some((name, term)) = associated_ty {
395 if let Some(stripped) = constraint.strip_suffix('>') {
398 constraint = format!("{stripped}, {name} = {term}>");
399 } else {
400 constraint.push_str(&format!("<{name} = {term}>"));
401 }
402 }
403
404 if suggest_constraining_type_param(
405 self.tcx,
406 generics,
407 err,
408 ¶m_name,
409 &constraint,
410 Some(trait_pred.def_id()),
411 None,
412 ) {
413 return;
414 }
415 }
416
417 hir::Node::TraitItem(hir::TraitItem {
418 generics,
419 kind: hir::TraitItemKind::Fn(..),
420 ..
421 })
422 | hir::Node::ImplItem(hir::ImplItem {
423 generics,
424 impl_kind: hir::ImplItemImplKind::Inherent { .. },
425 kind: hir::ImplItemKind::Fn(..),
426 ..
427 }) if finder.can_suggest_bound(generics) => {
428 suggest_arbitrary_trait_bound(
430 self.tcx,
431 generics,
432 err,
433 trait_pred,
434 associated_ty,
435 );
436 }
437 hir::Node::Item(hir::Item {
438 kind:
439 hir::ItemKind::Struct(_, generics, _)
440 | hir::ItemKind::Enum(_, generics, _)
441 | hir::ItemKind::Union(_, generics, _)
442 | hir::ItemKind::Trait(_, _, _, _, generics, ..)
443 | hir::ItemKind::Impl(hir::Impl { generics, .. })
444 | hir::ItemKind::Fn { generics, .. }
445 | hir::ItemKind::TyAlias(_, generics, _)
446 | hir::ItemKind::Const(_, generics, _, _)
447 | hir::ItemKind::TraitAlias(_, generics, _),
448 ..
449 }) if finder.can_suggest_bound(generics) => {
450 if suggest_arbitrary_trait_bound(
452 self.tcx,
453 generics,
454 err,
455 trait_pred,
456 associated_ty,
457 ) {
458 return;
459 }
460 }
461 hir::Node::Crate(..) => return,
462
463 _ => {}
464 }
465 body_id = self.tcx.local_parent(body_id);
466 }
467 }
468
469 pub(super) fn suggest_dereferences(
472 &self,
473 obligation: &PredicateObligation<'tcx>,
474 err: &mut Diag<'_>,
475 trait_pred: ty::PolyTraitPredicate<'tcx>,
476 ) -> bool {
477 let mut code = obligation.cause.code();
478 if let ObligationCauseCode::FunctionArg { arg_hir_id, call_hir_id, .. } = code
479 && let Some(typeck_results) = &self.typeck_results
480 && let hir::Node::Expr(expr) = self.tcx.hir_node(*arg_hir_id)
481 && let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr)
482 {
483 let mut real_trait_pred = trait_pred;
487 while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() {
488 code = parent_code;
489 if let Some(parent_trait_pred) = parent_trait_pred {
490 real_trait_pred = parent_trait_pred;
491 }
492 }
493
494 let real_ty = self.tcx.instantiate_bound_regions_with_erased(real_trait_pred.self_ty());
497 if !self.can_eq(obligation.param_env, real_ty, arg_ty) {
498 return false;
499 }
500
501 let (is_under_ref, base_ty, span) = match expr.kind {
508 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, subexpr)
509 if let &ty::Ref(region, base_ty, hir::Mutability::Not) = real_ty.kind() =>
510 {
511 (Some(region), base_ty, subexpr.span)
512 }
513 hir::ExprKind::AddrOf(..) => return false,
515 _ => (None, real_ty, obligation.cause.span),
516 };
517
518 let autoderef = (self.autoderef_steps)(base_ty);
519 let mut is_boxed = base_ty.is_box();
520 if let Some(steps) = autoderef.into_iter().position(|(mut ty, obligations)| {
521 let can_deref = is_under_ref.is_some()
524 || self.type_is_copy_modulo_regions(obligation.param_env, ty)
525 || ty.is_numeric() || is_boxed && self.type_is_sized_modulo_regions(obligation.param_env, ty);
527 is_boxed &= ty.is_box();
528
529 if let Some(region) = is_under_ref {
531 ty = Ty::new_ref(self.tcx, region, ty, hir::Mutability::Not);
532 }
533
534 let real_trait_pred_and_ty =
536 real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty));
537 let obligation = self.mk_trait_obligation_with_new_self_ty(
538 obligation.param_env,
539 real_trait_pred_and_ty,
540 );
541
542 can_deref
543 && obligations
544 .iter()
545 .chain([&obligation])
546 .all(|obligation| self.predicate_may_hold(obligation))
547 }) && steps > 0
548 {
549 let derefs = "*".repeat(steps);
550 let msg = "consider dereferencing here";
551 let call_node = self.tcx.hir_node(*call_hir_id);
552 let is_receiver = matches!(
553 call_node,
554 Node::Expr(hir::Expr {
555 kind: hir::ExprKind::MethodCall(_, receiver_expr, ..),
556 ..
557 })
558 if receiver_expr.hir_id == *arg_hir_id
559 );
560 if is_receiver {
561 err.multipart_suggestion_verbose(
562 msg,
563 vec![
564 (span.shrink_to_lo(), format!("({derefs}")),
565 (span.shrink_to_hi(), ")".to_string()),
566 ],
567 Applicability::MachineApplicable,
568 )
569 } else {
570 err.span_suggestion_verbose(
571 span.shrink_to_lo(),
572 msg,
573 derefs,
574 Applicability::MachineApplicable,
575 )
576 };
577 return true;
578 }
579 } else if let (
580 ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, .. },
581 predicate,
582 ) = code.peel_derives_with_predicate()
583 && let Some(typeck_results) = &self.typeck_results
584 && let hir::Node::Expr(lhs) = self.tcx.hir_node(*lhs_hir_id)
585 && let hir::Node::Expr(rhs) = self.tcx.hir_node(*rhs_hir_id)
586 && let Some(rhs_ty) = typeck_results.expr_ty_opt(rhs)
587 && let trait_pred = predicate.unwrap_or(trait_pred)
588 && hir::lang_items::BINARY_OPERATORS
590 .iter()
591 .filter_map(|&op| self.tcx.lang_items().get(op))
592 .any(|op| {
593 op == trait_pred.skip_binder().trait_ref.def_id
594 })
595 {
596 let trait_pred = predicate.unwrap_or(trait_pred);
599 let lhs_ty = self.tcx.instantiate_bound_regions_with_erased(trait_pred.self_ty());
600 let lhs_autoderef = (self.autoderef_steps)(lhs_ty);
601 let rhs_autoderef = (self.autoderef_steps)(rhs_ty);
602 let first_lhs = lhs_autoderef.first().unwrap().clone();
603 let first_rhs = rhs_autoderef.first().unwrap().clone();
604 let mut autoderefs = lhs_autoderef
605 .into_iter()
606 .enumerate()
607 .rev()
608 .zip_longest(rhs_autoderef.into_iter().enumerate().rev())
609 .map(|t| match t {
610 EitherOrBoth::Both(a, b) => (a, b),
611 EitherOrBoth::Left(a) => (a, (0, first_rhs.clone())),
612 EitherOrBoth::Right(b) => ((0, first_lhs.clone()), b),
613 })
614 .rev();
615 if let Some((lsteps, rsteps)) =
616 autoderefs.find_map(|((lsteps, (l_ty, _)), (rsteps, (r_ty, _)))| {
617 let trait_pred_and_ty = trait_pred.map_bound(|inner| {
621 (
622 ty::TraitPredicate {
623 trait_ref: ty::TraitRef::new_from_args(
624 self.tcx,
625 inner.trait_ref.def_id,
626 self.tcx.mk_args(
627 &[&[l_ty.into(), r_ty.into()], &inner.trait_ref.args[2..]]
628 .concat(),
629 ),
630 ),
631 ..inner
632 },
633 l_ty,
634 )
635 });
636 let obligation = self.mk_trait_obligation_with_new_self_ty(
637 obligation.param_env,
638 trait_pred_and_ty,
639 );
640 self.predicate_may_hold(&obligation).then_some(match (lsteps, rsteps) {
641 (_, 0) => (Some(lsteps), None),
642 (0, _) => (None, Some(rsteps)),
643 _ => (Some(lsteps), Some(rsteps)),
644 })
645 })
646 {
647 let make_sugg = |mut expr: &Expr<'_>, mut steps| {
648 let mut prefix_span = expr.span.shrink_to_lo();
649 let mut msg = "consider dereferencing here";
650 if let hir::ExprKind::AddrOf(_, _, inner) = expr.kind {
651 msg = "consider removing the borrow and dereferencing instead";
652 if let hir::ExprKind::AddrOf(..) = inner.kind {
653 msg = "consider removing the borrows and dereferencing instead";
654 }
655 }
656 while let hir::ExprKind::AddrOf(_, _, inner) = expr.kind
657 && steps > 0
658 {
659 prefix_span = prefix_span.with_hi(inner.span.lo());
660 expr = inner;
661 steps -= 1;
662 }
663 if steps == 0 {
665 return (
666 msg.trim_end_matches(" and dereferencing instead"),
667 vec![(prefix_span, String::new())],
668 );
669 }
670 let derefs = "*".repeat(steps);
671 let needs_parens = steps > 0
672 && match expr.kind {
673 hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
674 _ if is_range_literal(expr) => true,
675 _ => false,
676 };
677 let mut suggestion = if needs_parens {
678 vec![
679 (
680 expr.span.with_lo(prefix_span.hi()).shrink_to_lo(),
681 format!("{derefs}("),
682 ),
683 (expr.span.shrink_to_hi(), ")".to_string()),
684 ]
685 } else {
686 vec![(
687 expr.span.with_lo(prefix_span.hi()).shrink_to_lo(),
688 format!("{derefs}"),
689 )]
690 };
691 if !prefix_span.is_empty() {
693 suggestion.push((prefix_span, String::new()));
694 }
695 (msg, suggestion)
696 };
697
698 if let Some(lsteps) = lsteps
699 && let Some(rsteps) = rsteps
700 && lsteps > 0
701 && rsteps > 0
702 {
703 let mut suggestion = make_sugg(lhs, lsteps).1;
704 suggestion.append(&mut make_sugg(rhs, rsteps).1);
705 err.multipart_suggestion_verbose(
706 "consider dereferencing both sides of the expression",
707 suggestion,
708 Applicability::MachineApplicable,
709 );
710 return true;
711 } else if let Some(lsteps) = lsteps
712 && lsteps > 0
713 {
714 let (msg, suggestion) = make_sugg(lhs, lsteps);
715 err.multipart_suggestion_verbose(
716 msg,
717 suggestion,
718 Applicability::MachineApplicable,
719 );
720 return true;
721 } else if let Some(rsteps) = rsteps
722 && rsteps > 0
723 {
724 let (msg, suggestion) = make_sugg(rhs, rsteps);
725 err.multipart_suggestion_verbose(
726 msg,
727 suggestion,
728 Applicability::MachineApplicable,
729 );
730 return true;
731 }
732 }
733 }
734 false
735 }
736
737 fn get_closure_name(
741 &self,
742 def_id: DefId,
743 err: &mut Diag<'_>,
744 msg: Cow<'static, str>,
745 ) -> Option<Symbol> {
746 let get_name = |err: &mut Diag<'_>, kind: &hir::PatKind<'_>| -> Option<Symbol> {
747 match &kind {
750 hir::PatKind::Binding(hir::BindingMode::NONE, _, ident, None) => Some(ident.name),
751 _ => {
752 err.note(msg);
753 None
754 }
755 }
756 };
757
758 let hir_id = self.tcx.local_def_id_to_hir_id(def_id.as_local()?);
759 match self.tcx.parent_hir_node(hir_id) {
760 hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Let(local), .. }) => {
761 get_name(err, &local.pat.kind)
762 }
763 hir::Node::LetStmt(local) => get_name(err, &local.pat.kind),
766 _ => None,
767 }
768 }
769
770 pub(super) fn suggest_fn_call(
774 &self,
775 obligation: &PredicateObligation<'tcx>,
776 err: &mut Diag<'_>,
777 trait_pred: ty::PolyTraitPredicate<'tcx>,
778 ) -> bool {
779 if self.typeck_results.is_none() {
782 return false;
783 }
784
785 if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) =
786 obligation.predicate.kind().skip_binder()
787 && self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Sized)
788 {
789 return false;
791 }
792
793 let self_ty = self.instantiate_binder_with_fresh_vars(
794 DUMMY_SP,
795 BoundRegionConversionTime::FnCall,
796 trait_pred.self_ty(),
797 );
798
799 let Some((def_id_or_name, output, inputs)) =
800 self.extract_callable_info(obligation.cause.body_id, obligation.param_env, self_ty)
801 else {
802 return false;
803 };
804
805 let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output));
807
808 let new_obligation =
809 self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);
810 if !self.predicate_must_hold_modulo_regions(&new_obligation) {
811 return false;
812 }
813
814 let msg = match def_id_or_name {
816 DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
817 DefKind::Ctor(CtorOf::Struct, _) => {
818 Cow::from("use parentheses to construct this tuple struct")
819 }
820 DefKind::Ctor(CtorOf::Variant, _) => {
821 Cow::from("use parentheses to construct this tuple variant")
822 }
823 kind => Cow::from(format!(
824 "use parentheses to call this {}",
825 self.tcx.def_kind_descr(kind, def_id)
826 )),
827 },
828 DefIdOrName::Name(name) => Cow::from(format!("use parentheses to call this {name}")),
829 };
830
831 let args = inputs
832 .into_iter()
833 .map(|ty| {
834 if ty.is_suggestable(self.tcx, false) {
835 format!("/* {ty} */")
836 } else {
837 "/* value */".to_string()
838 }
839 })
840 .collect::<Vec<_>>()
841 .join(", ");
842
843 if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArg { .. })
844 && obligation.cause.span.can_be_used_for_suggestions()
845 {
846 let (span, sugg) = if let Some(snippet) =
847 self.tcx.sess.source_map().span_to_snippet(obligation.cause.span).ok()
848 && snippet.starts_with("|")
849 {
850 (obligation.cause.span, format!("({snippet})({args})"))
851 } else {
852 (obligation.cause.span.shrink_to_hi(), format!("({args})"))
853 };
854
855 err.span_suggestion_verbose(span, msg, sugg, Applicability::HasPlaceholders);
860 } else if let DefIdOrName::DefId(def_id) = def_id_or_name {
861 let name = match self.tcx.hir_get_if_local(def_id) {
862 Some(hir::Node::Expr(hir::Expr {
863 kind: hir::ExprKind::Closure(hir::Closure { fn_decl_span, .. }),
864 ..
865 })) => {
866 err.span_label(*fn_decl_span, "consider calling this closure");
867 let Some(name) = self.get_closure_name(def_id, err, msg.clone()) else {
868 return false;
869 };
870 name.to_string()
871 }
872 Some(hir::Node::Item(hir::Item {
873 kind: hir::ItemKind::Fn { ident, .. }, ..
874 })) => {
875 err.span_label(ident.span, "consider calling this function");
876 ident.to_string()
877 }
878 Some(hir::Node::Ctor(..)) => {
879 let name = self.tcx.def_path_str(def_id);
880 err.span_label(
881 self.tcx.def_span(def_id),
882 format!("consider calling the constructor for `{name}`"),
883 );
884 name
885 }
886 _ => return false,
887 };
888 err.help(format!("{msg}: `{name}({args})`"));
889 }
890 true
891 }
892
893 pub(super) fn check_for_binding_assigned_block_without_tail_expression(
894 &self,
895 obligation: &PredicateObligation<'tcx>,
896 err: &mut Diag<'_>,
897 trait_pred: ty::PolyTraitPredicate<'tcx>,
898 ) {
899 let mut span = obligation.cause.span;
900 while span.from_expansion() {
901 span.remove_mark();
903 }
904 let mut expr_finder = FindExprBySpan::new(span, self.tcx);
905 let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else {
906 return;
907 };
908 expr_finder.visit_expr(body.value);
909 let Some(expr) = expr_finder.result else {
910 return;
911 };
912 let Some(typeck) = &self.typeck_results else {
913 return;
914 };
915 let Some(ty) = typeck.expr_ty_adjusted_opt(expr) else {
916 return;
917 };
918 if !ty.is_unit() {
919 return;
920 };
921 let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else {
922 return;
923 };
924 let Res::Local(hir_id) = path.res else {
925 return;
926 };
927 let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else {
928 return;
929 };
930 let hir::Node::LetStmt(hir::LetStmt { ty: None, init: Some(init), .. }) =
931 self.tcx.parent_hir_node(pat.hir_id)
932 else {
933 return;
934 };
935 let hir::ExprKind::Block(block, None) = init.kind else {
936 return;
937 };
938 if block.expr.is_some() {
939 return;
940 }
941 let [.., stmt] = block.stmts else {
942 err.span_label(block.span, "this empty block is missing a tail expression");
943 return;
944 };
945 let hir::StmtKind::Semi(tail_expr) = stmt.kind else {
946 return;
947 };
948 let Some(ty) = typeck.expr_ty_opt(tail_expr) else {
949 err.span_label(block.span, "this block is missing a tail expression");
950 return;
951 };
952 let ty = self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(ty));
953 let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, ty));
954
955 let new_obligation =
956 self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);
957 if self.predicate_must_hold_modulo_regions(&new_obligation) {
958 err.span_suggestion_short(
959 stmt.span.with_lo(tail_expr.span.hi()),
960 "remove this semicolon",
961 "",
962 Applicability::MachineApplicable,
963 );
964 } else {
965 err.span_label(block.span, "this block is missing a tail expression");
966 }
967 }
968
969 pub(super) fn suggest_add_clone_to_arg(
970 &self,
971 obligation: &PredicateObligation<'tcx>,
972 err: &mut Diag<'_>,
973 trait_pred: ty::PolyTraitPredicate<'tcx>,
974 ) -> bool {
975 let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
976 self.enter_forall(self_ty, |ty: Ty<'_>| {
977 let Some(generics) = self.tcx.hir_get_generics(obligation.cause.body_id) else {
978 return false;
979 };
980 let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false };
981 let ty::Param(param) = inner_ty.kind() else { return false };
982 let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code()
983 else {
984 return false;
985 };
986
987 let clone_trait = self.tcx.require_lang_item(LangItem::Clone, obligation.cause.span);
988 let has_clone = |ty| {
989 self.type_implements_trait(clone_trait, [ty], obligation.param_env)
990 .must_apply_modulo_regions()
991 };
992
993 let existing_clone_call = match self.tcx.hir_node(*arg_hir_id) {
994 Node::Expr(Expr { kind: hir::ExprKind::Path(_), .. }) => None,
996 Node::Expr(Expr {
999 kind:
1000 hir::ExprKind::MethodCall(
1001 hir::PathSegment { ident, .. },
1002 _receiver,
1003 [],
1004 call_span,
1005 ),
1006 hir_id,
1007 ..
1008 }) if ident.name == sym::clone
1009 && !call_span.from_expansion()
1010 && !has_clone(*inner_ty) =>
1011 {
1012 let Some(typeck_results) = self.typeck_results.as_ref() else { return false };
1014 let Some((DefKind::AssocFn, did)) = typeck_results.type_dependent_def(*hir_id)
1015 else {
1016 return false;
1017 };
1018 if self.tcx.trait_of_assoc(did) != Some(clone_trait) {
1019 return false;
1020 }
1021 Some(ident.span)
1022 }
1023 _ => return false,
1024 };
1025
1026 let new_obligation = self.mk_trait_obligation_with_new_self_ty(
1027 obligation.param_env,
1028 trait_pred.map_bound(|trait_pred| (trait_pred, *inner_ty)),
1029 );
1030
1031 if self.predicate_may_hold(&new_obligation) && has_clone(ty) {
1032 if !has_clone(param.to_ty(self.tcx)) {
1033 suggest_constraining_type_param(
1034 self.tcx,
1035 generics,
1036 err,
1037 param.name.as_str(),
1038 "Clone",
1039 Some(clone_trait),
1040 None,
1041 );
1042 }
1043 if let Some(existing_clone_call) = existing_clone_call {
1044 err.span_note(
1045 existing_clone_call,
1046 format!(
1047 "this `clone()` copies the reference, \
1048 which does not do anything, \
1049 because `{inner_ty}` does not implement `Clone`"
1050 ),
1051 );
1052 } else {
1053 err.span_suggestion_verbose(
1054 obligation.cause.span.shrink_to_hi(),
1055 "consider using clone here",
1056 ".clone()".to_string(),
1057 Applicability::MaybeIncorrect,
1058 );
1059 }
1060 return true;
1061 }
1062 false
1063 })
1064 }
1065
1066 pub fn extract_callable_info(
1070 &self,
1071 body_id: LocalDefId,
1072 param_env: ty::ParamEnv<'tcx>,
1073 found: Ty<'tcx>,
1074 ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
1075 let Some((def_id_or_name, output, inputs)) =
1077 (self.autoderef_steps)(found).into_iter().find_map(|(found, _)| match *found.kind() {
1078 ty::FnPtr(sig_tys, _) => Some((
1079 DefIdOrName::Name("function pointer"),
1080 sig_tys.output(),
1081 sig_tys.inputs(),
1082 )),
1083 ty::FnDef(def_id, _) => {
1084 let fn_sig = found.fn_sig(self.tcx);
1085 Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
1086 }
1087 ty::Closure(def_id, args) => {
1088 let fn_sig = args.as_closure().sig();
1089 Some((
1090 DefIdOrName::DefId(def_id),
1091 fn_sig.output(),
1092 fn_sig.inputs().map_bound(|inputs| inputs[0].tuple_fields().as_slice()),
1093 ))
1094 }
1095 ty::CoroutineClosure(def_id, args) => {
1096 let sig_parts = args.as_coroutine_closure().coroutine_closure_sig();
1097 Some((
1098 DefIdOrName::DefId(def_id),
1099 sig_parts.map_bound(|sig| {
1100 sig.to_coroutine(
1101 self.tcx,
1102 args.as_coroutine_closure().parent_args(),
1103 self.next_ty_var(DUMMY_SP),
1106 self.tcx.coroutine_for_closure(def_id),
1107 self.next_ty_var(DUMMY_SP),
1108 )
1109 }),
1110 sig_parts.map_bound(|sig| sig.tupled_inputs_ty.tuple_fields().as_slice()),
1111 ))
1112 }
1113 ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
1114 self.tcx.item_self_bounds(def_id).instantiate(self.tcx, args).iter().find_map(
1115 |pred| {
1116 if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
1117 && self
1118 .tcx
1119 .is_lang_item(proj.projection_term.def_id, LangItem::FnOnceOutput)
1120 && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()
1122 {
1123 Some((
1124 DefIdOrName::DefId(def_id),
1125 pred.kind().rebind(proj.term.expect_type()),
1126 pred.kind().rebind(args.as_slice()),
1127 ))
1128 } else {
1129 None
1130 }
1131 },
1132 )
1133 }
1134 ty::Dynamic(data, _, ty::Dyn) => data.iter().find_map(|pred| {
1135 if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
1136 && self.tcx.is_lang_item(proj.def_id, LangItem::FnOnceOutput)
1137 && let ty::Tuple(args) = proj.args.type_at(0).kind()
1139 {
1140 Some((
1141 DefIdOrName::Name("trait object"),
1142 pred.rebind(proj.term.expect_type()),
1143 pred.rebind(args.as_slice()),
1144 ))
1145 } else {
1146 None
1147 }
1148 }),
1149 ty::Param(param) => {
1150 let generics = self.tcx.generics_of(body_id);
1151 let name = if generics.count() > param.index as usize
1152 && let def = generics.param_at(param.index as usize, self.tcx)
1153 && matches!(def.kind, ty::GenericParamDefKind::Type { .. })
1154 && def.name == param.name
1155 {
1156 DefIdOrName::DefId(def.def_id)
1157 } else {
1158 DefIdOrName::Name("type parameter")
1159 };
1160 param_env.caller_bounds().iter().find_map(|pred| {
1161 if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
1162 && self
1163 .tcx
1164 .is_lang_item(proj.projection_term.def_id, LangItem::FnOnceOutput)
1165 && proj.projection_term.self_ty() == found
1166 && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()
1168 {
1169 Some((
1170 name,
1171 pred.kind().rebind(proj.term.expect_type()),
1172 pred.kind().rebind(args.as_slice()),
1173 ))
1174 } else {
1175 None
1176 }
1177 })
1178 }
1179 _ => None,
1180 })
1181 else {
1182 return None;
1183 };
1184
1185 let output = self.instantiate_binder_with_fresh_vars(
1186 DUMMY_SP,
1187 BoundRegionConversionTime::FnCall,
1188 output,
1189 );
1190 let inputs = inputs
1191 .skip_binder()
1192 .iter()
1193 .map(|ty| {
1194 self.instantiate_binder_with_fresh_vars(
1195 DUMMY_SP,
1196 BoundRegionConversionTime::FnCall,
1197 inputs.rebind(*ty),
1198 )
1199 })
1200 .collect();
1201
1202 let InferOk { value: output, obligations: _ } =
1206 self.at(&ObligationCause::dummy(), param_env).normalize(output);
1207
1208 if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }
1209 }
1210
1211 pub(super) fn suggest_add_reference_to_arg(
1212 &self,
1213 obligation: &PredicateObligation<'tcx>,
1214 err: &mut Diag<'_>,
1215 poly_trait_pred: ty::PolyTraitPredicate<'tcx>,
1216 has_custom_message: bool,
1217 ) -> bool {
1218 let span = obligation.cause.span;
1219 let param_env = obligation.param_env;
1220
1221 let mk_result = |trait_pred_and_new_ty| {
1222 let obligation =
1223 self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
1224 self.predicate_must_hold_modulo_regions(&obligation)
1225 };
1226
1227 let code = match obligation.cause.code() {
1228 ObligationCauseCode::FunctionArg { parent_code, .. } => parent_code,
1229 c @ ObligationCauseCode::WhereClauseInExpr(_, _, hir_id, _)
1232 if self.tcx.hir_span(*hir_id).lo() == span.lo() =>
1233 {
1234 if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(*hir_id)
1238 && let hir::ExprKind::Call(base, _) = expr.kind
1239 && let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, segment)) = base.kind
1240 && let hir::Node::Expr(outer) = self.tcx.parent_hir_node(expr.hir_id)
1241 && let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mtbl, _) = outer.kind
1242 && ty.span == span
1243 {
1244 let trait_pred_and_imm_ref = poly_trait_pred.map_bound(|p| {
1250 (p, Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, p.self_ty()))
1251 });
1252 let trait_pred_and_mut_ref = poly_trait_pred.map_bound(|p| {
1253 (p, Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, p.self_ty()))
1254 });
1255
1256 let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref);
1257 let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);
1258 let sugg_msg = |pre: &str| {
1259 format!(
1260 "you likely meant to call the associated function `{FN}` for type \
1261 `&{pre}{TY}`, but the code as written calls associated function `{FN}` on \
1262 type `{TY}`",
1263 FN = segment.ident,
1264 TY = poly_trait_pred.self_ty(),
1265 )
1266 };
1267 match (imm_ref_self_ty_satisfies_pred, mut_ref_self_ty_satisfies_pred, mtbl) {
1268 (true, _, hir::Mutability::Not) | (_, true, hir::Mutability::Mut) => {
1269 err.multipart_suggestion_verbose(
1270 sugg_msg(mtbl.prefix_str()),
1271 vec![
1272 (outer.span.shrink_to_lo(), "<".to_string()),
1273 (span.shrink_to_hi(), ">".to_string()),
1274 ],
1275 Applicability::MachineApplicable,
1276 );
1277 }
1278 (true, _, hir::Mutability::Mut) => {
1279 err.multipart_suggestion_verbose(
1281 sugg_msg("mut "),
1282 vec![
1283 (outer.span.shrink_to_lo().until(span), "<&".to_string()),
1284 (span.shrink_to_hi(), ">".to_string()),
1285 ],
1286 Applicability::MachineApplicable,
1287 );
1288 }
1289 (_, true, hir::Mutability::Not) => {
1290 err.multipart_suggestion_verbose(
1291 sugg_msg(""),
1292 vec![
1293 (outer.span.shrink_to_lo().until(span), "<&mut ".to_string()),
1294 (span.shrink_to_hi(), ">".to_string()),
1295 ],
1296 Applicability::MachineApplicable,
1297 );
1298 }
1299 _ => {}
1300 }
1301 return false;
1303 }
1304 c
1305 }
1306 c if matches!(
1307 span.ctxt().outer_expn_data().kind,
1308 ExpnKind::Desugaring(DesugaringKind::ForLoop)
1309 ) =>
1310 {
1311 c
1312 }
1313 _ => return false,
1314 };
1315
1316 let mut never_suggest_borrow: Vec<_> =
1320 [LangItem::Copy, LangItem::Clone, LangItem::Unpin, LangItem::Sized]
1321 .iter()
1322 .filter_map(|lang_item| self.tcx.lang_items().get(*lang_item))
1323 .collect();
1324
1325 if let Some(def_id) = self.tcx.get_diagnostic_item(sym::Send) {
1326 never_suggest_borrow.push(def_id);
1327 }
1328
1329 let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>,
1331 blacklist: &[DefId]|
1332 -> bool {
1333 if blacklist.contains(&old_pred.def_id()) {
1334 return false;
1335 }
1336 let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| {
1338 (
1339 trait_pred,
1340 Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, trait_pred.self_ty()),
1341 )
1342 });
1343 let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| {
1344 (
1345 trait_pred,
1346 Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, trait_pred.self_ty()),
1347 )
1348 });
1349
1350 let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref);
1351 let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);
1352
1353 let (ref_inner_ty_satisfies_pred, ref_inner_ty_is_mut) =
1354 if let ObligationCauseCode::WhereClauseInExpr(..) = obligation.cause.code()
1355 && let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind()
1356 {
1357 (
1358 mk_result(old_pred.map_bound(|trait_pred| (trait_pred, *ty))),
1359 mutability.is_mut(),
1360 )
1361 } else {
1362 (false, false)
1363 };
1364
1365 let is_immut = imm_ref_self_ty_satisfies_pred
1366 || (ref_inner_ty_satisfies_pred && !ref_inner_ty_is_mut);
1367 let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_is_mut;
1368 if !is_immut && !is_mut {
1369 return false;
1370 }
1371 let Ok(_snippet) = self.tcx.sess.source_map().span_to_snippet(span) else {
1372 return false;
1373 };
1374 if !matches!(
1382 span.ctxt().outer_expn_data().kind,
1383 ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
1384 ) {
1385 return false;
1386 }
1387 let mut label = || {
1394 let msg = format!(
1395 "the trait bound `{}` is not satisfied",
1396 self.tcx.short_string(old_pred, err.long_ty_path()),
1397 );
1398 let self_ty_str =
1399 self.tcx.short_string(old_pred.self_ty().skip_binder(), err.long_ty_path());
1400 let trait_path = self
1401 .tcx
1402 .short_string(old_pred.print_modifiers_and_trait_path(), err.long_ty_path());
1403
1404 if has_custom_message {
1405 err.note(msg);
1406 } else {
1407 err.messages = vec![(rustc_errors::DiagMessage::from(msg), Style::NoStyle)];
1408 }
1409 err.span_label(
1410 span,
1411 format!("the trait `{trait_path}` is not implemented for `{self_ty_str}`"),
1412 );
1413 };
1414
1415 let mut sugg_prefixes = vec![];
1416 if is_immut {
1417 sugg_prefixes.push("&");
1418 }
1419 if is_mut {
1420 sugg_prefixes.push("&mut ");
1421 }
1422 let sugg_msg = format!(
1423 "consider{} borrowing here",
1424 if is_mut && !is_immut { " mutably" } else { "" },
1425 );
1426
1427 let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else {
1431 return false;
1432 };
1433 let mut expr_finder = FindExprBySpan::new(span, self.tcx);
1434 expr_finder.visit_expr(body.value);
1435
1436 if let Some(ty) = expr_finder.ty_result {
1437 if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(ty.hir_id)
1438 && let hir::ExprKind::Path(hir::QPath::TypeRelative(_, _)) = expr.kind
1439 && ty.span == span
1440 {
1441 label();
1444 err.multipart_suggestions(
1445 sugg_msg,
1446 sugg_prefixes.into_iter().map(|sugg_prefix| {
1447 vec![
1448 (span.shrink_to_lo(), format!("<{sugg_prefix}")),
1449 (span.shrink_to_hi(), ">".to_string()),
1450 ]
1451 }),
1452 Applicability::MaybeIncorrect,
1453 );
1454 return true;
1455 }
1456 return false;
1457 }
1458 let Some(expr) = expr_finder.result else {
1459 return false;
1460 };
1461 if let hir::ExprKind::AddrOf(_, _, _) = expr.kind {
1462 return false;
1463 }
1464 let needs_parens_post = expr_needs_parens(expr);
1465 let needs_parens_pre = match self.tcx.parent_hir_node(expr.hir_id) {
1466 Node::Expr(e)
1467 if let hir::ExprKind::MethodCall(_, base, _, _) = e.kind
1468 && base.hir_id == expr.hir_id =>
1469 {
1470 true
1471 }
1472 _ => false,
1473 };
1474
1475 label();
1476 let suggestions = sugg_prefixes.into_iter().map(|sugg_prefix| {
1477 match (needs_parens_pre, needs_parens_post) {
1478 (false, false) => vec![(span.shrink_to_lo(), sugg_prefix.to_string())],
1479 (false, true) => vec![
1482 (span.shrink_to_lo(), format!("{sugg_prefix}(")),
1483 (span.shrink_to_hi(), ")".to_string()),
1484 ],
1485 (true, false) => vec![
1488 (span.shrink_to_lo(), format!("({sugg_prefix}")),
1489 (span.shrink_to_hi(), ")".to_string()),
1490 ],
1491 (true, true) => vec![
1492 (span.shrink_to_lo(), format!("({sugg_prefix}(")),
1493 (span.shrink_to_hi(), "))".to_string()),
1494 ],
1495 }
1496 });
1497 err.multipart_suggestions(sugg_msg, suggestions, Applicability::MaybeIncorrect);
1498 return true;
1499 };
1500
1501 if let ObligationCauseCode::ImplDerived(cause) = &*code {
1502 try_borrowing(cause.derived.parent_trait_pred, &[])
1503 } else if let ObligationCauseCode::WhereClause(..)
1504 | ObligationCauseCode::WhereClauseInExpr(..) = code
1505 {
1506 try_borrowing(poly_trait_pred, &never_suggest_borrow)
1507 } else {
1508 false
1509 }
1510 }
1511
1512 pub(super) fn suggest_borrowing_for_object_cast(
1514 &self,
1515 err: &mut Diag<'_>,
1516 obligation: &PredicateObligation<'tcx>,
1517 self_ty: Ty<'tcx>,
1518 target_ty: Ty<'tcx>,
1519 ) {
1520 let ty::Ref(_, object_ty, hir::Mutability::Not) = target_ty.kind() else {
1521 return;
1522 };
1523 let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else {
1524 return;
1525 };
1526 let self_ref_ty = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, self_ty);
1527
1528 for predicate in predicates.iter() {
1529 if !self.predicate_must_hold_modulo_regions(
1530 &obligation.with(self.tcx, predicate.with_self_ty(self.tcx, self_ref_ty)),
1531 ) {
1532 return;
1533 }
1534 }
1535
1536 err.span_suggestion_verbose(
1537 obligation.cause.span.shrink_to_lo(),
1538 format!(
1539 "consider borrowing the value, since `&{self_ty}` can be coerced into `{target_ty}`"
1540 ),
1541 "&",
1542 Applicability::MaybeIncorrect,
1543 );
1544 }
1545
1546 pub(super) fn suggest_remove_reference(
1549 &self,
1550 obligation: &PredicateObligation<'tcx>,
1551 err: &mut Diag<'_>,
1552 trait_pred: ty::PolyTraitPredicate<'tcx>,
1553 ) -> bool {
1554 let mut span = obligation.cause.span;
1555 let mut trait_pred = trait_pred;
1556 let mut code = obligation.cause.code();
1557 while let Some((c, Some(parent_trait_pred))) = code.parent_with_predicate() {
1558 code = c;
1561 trait_pred = parent_trait_pred;
1562 }
1563 while span.desugaring_kind().is_some() {
1564 span.remove_mark();
1566 }
1567 let mut expr_finder = super::FindExprBySpan::new(span, self.tcx);
1568 let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else {
1569 return false;
1570 };
1571 expr_finder.visit_expr(body.value);
1572 let mut maybe_suggest = |suggested_ty, count, suggestions| {
1573 let trait_pred_and_suggested_ty =
1575 trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
1576
1577 let new_obligation = self.mk_trait_obligation_with_new_self_ty(
1578 obligation.param_env,
1579 trait_pred_and_suggested_ty,
1580 );
1581
1582 if self.predicate_may_hold(&new_obligation) {
1583 let msg = if count == 1 {
1584 "consider removing the leading `&`-reference".to_string()
1585 } else {
1586 format!("consider removing {count} leading `&`-references")
1587 };
1588
1589 err.multipart_suggestion_verbose(
1590 msg,
1591 suggestions,
1592 Applicability::MachineApplicable,
1593 );
1594 true
1595 } else {
1596 false
1597 }
1598 };
1599
1600 let mut count = 0;
1603 let mut suggestions = vec![];
1604 let mut suggested_ty = trait_pred.self_ty().skip_binder();
1606 if let Some(mut hir_ty) = expr_finder.ty_result {
1607 while let hir::TyKind::Ref(_, mut_ty) = &hir_ty.kind {
1608 count += 1;
1609 let span = hir_ty.span.until(mut_ty.ty.span);
1610 suggestions.push((span, String::new()));
1611
1612 let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
1613 break;
1614 };
1615 suggested_ty = *inner_ty;
1616
1617 hir_ty = mut_ty.ty;
1618
1619 if maybe_suggest(suggested_ty, count, suggestions.clone()) {
1620 return true;
1621 }
1622 }
1623 }
1624
1625 let Some(mut expr) = expr_finder.result else {
1627 return false;
1628 };
1629 let mut count = 0;
1630 let mut suggestions = vec![];
1631 let mut suggested_ty = trait_pred.self_ty().skip_binder();
1633 'outer: loop {
1634 while let hir::ExprKind::AddrOf(_, _, borrowed) = expr.kind {
1635 count += 1;
1636 let span =
1637 if let Some(borrowed_span) = borrowed.span.find_ancestor_inside(expr.span) {
1638 expr.span.until(borrowed_span)
1639 } else {
1640 break 'outer;
1641 };
1642
1643 match self.tcx.sess.source_map().span_to_snippet(span) {
1646 Ok(snippet) if snippet.starts_with("&") => {}
1647 _ => break 'outer,
1648 }
1649
1650 suggestions.push((span, String::new()));
1651
1652 let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
1653 break 'outer;
1654 };
1655 suggested_ty = *inner_ty;
1656
1657 expr = borrowed;
1658
1659 if maybe_suggest(suggested_ty, count, suggestions.clone()) {
1660 return true;
1661 }
1662 }
1663 if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
1664 && let Res::Local(hir_id) = path.res
1665 && let hir::Node::Pat(binding) = self.tcx.hir_node(hir_id)
1666 && let hir::Node::LetStmt(local) = self.tcx.parent_hir_node(binding.hir_id)
1667 && let None = local.ty
1668 && let Some(binding_expr) = local.init
1669 {
1670 expr = binding_expr;
1671 } else {
1672 break 'outer;
1673 }
1674 }
1675 false
1676 }
1677
1678 pub(super) fn suggest_remove_await(
1679 &self,
1680 obligation: &PredicateObligation<'tcx>,
1681 err: &mut Diag<'_>,
1682 ) {
1683 if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives()
1684 && let hir::Node::Expr(expr) = self.tcx.hir_node(*hir_id)
1685 {
1686 if let Some((_, hir::Node::Expr(await_expr))) = self.tcx.hir_parent_iter(*hir_id).nth(1)
1693 && let Some(expr_span) = expr.span.find_ancestor_inside_same_ctxt(await_expr.span)
1694 {
1695 let removal_span = self
1696 .tcx
1697 .sess
1698 .source_map()
1699 .span_extend_while_whitespace(expr_span)
1700 .shrink_to_hi()
1701 .to(await_expr.span.shrink_to_hi());
1702 err.span_suggestion_verbose(
1703 removal_span,
1704 "remove the `.await`",
1705 "",
1706 Applicability::MachineApplicable,
1707 );
1708 } else {
1709 err.span_label(obligation.cause.span, "remove the `.await`");
1710 }
1711 if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr {
1713 if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
1714 obligation.predicate.kind().skip_binder()
1715 {
1716 err.span_label(*span, format!("this call returns `{}`", pred.self_ty()));
1717 }
1718 if let Some(typeck_results) = &self.typeck_results
1719 && let ty = typeck_results.expr_ty_adjusted(base)
1720 && let ty::FnDef(def_id, _args) = ty.kind()
1721 && let Some(hir::Node::Item(item)) = self.tcx.hir_get_if_local(*def_id)
1722 {
1723 let (ident, _, _, _) = item.expect_fn();
1724 let msg = format!("alternatively, consider making `fn {ident}` asynchronous");
1725 if item.vis_span.is_empty() {
1726 err.span_suggestion_verbose(
1727 item.span.shrink_to_lo(),
1728 msg,
1729 "async ",
1730 Applicability::MaybeIncorrect,
1731 );
1732 } else {
1733 err.span_suggestion_verbose(
1734 item.vis_span.shrink_to_hi(),
1735 msg,
1736 " async",
1737 Applicability::MaybeIncorrect,
1738 );
1739 }
1740 }
1741 }
1742 }
1743 }
1744
1745 pub(super) fn suggest_change_mut(
1748 &self,
1749 obligation: &PredicateObligation<'tcx>,
1750 err: &mut Diag<'_>,
1751 trait_pred: ty::PolyTraitPredicate<'tcx>,
1752 ) {
1753 let points_at_arg =
1754 matches!(obligation.cause.code(), ObligationCauseCode::FunctionArg { .. },);
1755
1756 let span = obligation.cause.span;
1757 if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
1758 let refs_number =
1759 snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count();
1760 if let Some('\'') = snippet.chars().filter(|c| !c.is_whitespace()).nth(refs_number) {
1761 return;
1763 }
1764 let trait_pred = self.resolve_vars_if_possible(trait_pred);
1765 if trait_pred.has_non_region_infer() {
1766 return;
1769 }
1770
1771 if let ty::Ref(region, t_type, mutability) = *trait_pred.skip_binder().self_ty().kind()
1773 {
1774 let suggested_ty = match mutability {
1775 hir::Mutability::Mut => Ty::new_imm_ref(self.tcx, region, t_type),
1776 hir::Mutability::Not => Ty::new_mut_ref(self.tcx, region, t_type),
1777 };
1778
1779 let trait_pred_and_suggested_ty =
1781 trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
1782
1783 let new_obligation = self.mk_trait_obligation_with_new_self_ty(
1784 obligation.param_env,
1785 trait_pred_and_suggested_ty,
1786 );
1787 let suggested_ty_would_satisfy_obligation = self
1788 .evaluate_obligation_no_overflow(&new_obligation)
1789 .must_apply_modulo_regions();
1790 if suggested_ty_would_satisfy_obligation {
1791 let sp = self
1792 .tcx
1793 .sess
1794 .source_map()
1795 .span_take_while(span, |c| c.is_whitespace() || *c == '&');
1796 if points_at_arg && mutability.is_not() && refs_number > 0 {
1797 if snippet
1799 .trim_start_matches(|c: char| c.is_whitespace() || c == '&')
1800 .starts_with("mut")
1801 {
1802 return;
1803 }
1804 err.span_suggestion_verbose(
1805 sp,
1806 "consider changing this borrow's mutability",
1807 "&mut ",
1808 Applicability::MachineApplicable,
1809 );
1810 } else {
1811 err.note(format!(
1812 "`{}` is implemented for `{}`, but not for `{}`",
1813 trait_pred.print_modifiers_and_trait_path(),
1814 suggested_ty,
1815 trait_pred.skip_binder().self_ty(),
1816 ));
1817 }
1818 }
1819 }
1820 }
1821 }
1822
1823 pub(super) fn suggest_semicolon_removal(
1824 &self,
1825 obligation: &PredicateObligation<'tcx>,
1826 err: &mut Diag<'_>,
1827 span: Span,
1828 trait_pred: ty::PolyTraitPredicate<'tcx>,
1829 ) -> bool {
1830 let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id);
1831 if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn {sig, body: body_id, .. }, .. }) = node
1832 && let hir::ExprKind::Block(blk, _) = &self.tcx.hir_body(*body_id).value.kind
1833 && sig.decl.output.span().overlaps(span)
1834 && blk.expr.is_none()
1835 && trait_pred.self_ty().skip_binder().is_unit()
1836 && let Some(stmt) = blk.stmts.last()
1837 && let hir::StmtKind::Semi(expr) = stmt.kind
1838 && let Some(typeck_results) = &self.typeck_results
1840 && let Some(ty) = typeck_results.expr_ty_opt(expr)
1841 && self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(
1842 obligation.param_env, trait_pred.map_bound(|trait_pred| (trait_pred, ty))
1843 ))
1844 {
1845 err.span_label(
1846 expr.span,
1847 format!(
1848 "this expression has type `{}`, which implements `{}`",
1849 ty,
1850 trait_pred.print_modifiers_and_trait_path()
1851 ),
1852 );
1853 err.span_suggestion(
1854 self.tcx.sess.source_map().end_point(stmt.span),
1855 "remove this semicolon",
1856 "",
1857 Applicability::MachineApplicable,
1858 );
1859 return true;
1860 }
1861 false
1862 }
1863
1864 pub(super) fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> {
1865 let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig, .. }, .. }) =
1866 self.tcx.hir_node_by_def_id(obligation.cause.body_id)
1867 else {
1868 return None;
1869 };
1870
1871 if let hir::FnRetTy::Return(ret_ty) = sig.decl.output { Some(ret_ty.span) } else { None }
1872 }
1873
1874 pub(super) fn suggest_impl_trait(
1878 &self,
1879 err: &mut Diag<'_>,
1880 obligation: &PredicateObligation<'tcx>,
1881 trait_pred: ty::PolyTraitPredicate<'tcx>,
1882 ) -> bool {
1883 let ObligationCauseCode::SizedReturnType = obligation.cause.code() else {
1884 return false;
1885 };
1886 let ty::Dynamic(_, _, ty::Dyn) = trait_pred.self_ty().skip_binder().kind() else {
1887 return false;
1888 };
1889
1890 err.code(E0746);
1891 err.primary_message("return type cannot be a trait object without pointer indirection");
1892 err.children.clear();
1893
1894 let span = obligation.cause.span;
1895 let body = self.tcx.hir_body_owned_by(obligation.cause.body_id);
1896
1897 let mut visitor = ReturnsVisitor::default();
1898 visitor.visit_body(&body);
1899
1900 let (pre, impl_span) = if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span)
1901 && snip.starts_with("dyn ")
1902 {
1903 ("", span.with_hi(span.lo() + BytePos(4)))
1904 } else {
1905 ("dyn ", span.shrink_to_lo())
1906 };
1907
1908 err.span_suggestion_verbose(
1909 impl_span,
1910 "consider returning an `impl Trait` instead of a `dyn Trait`",
1911 "impl ",
1912 Applicability::MaybeIncorrect,
1913 );
1914
1915 let mut sugg = vec![
1916 (span.shrink_to_lo(), format!("Box<{pre}")),
1917 (span.shrink_to_hi(), ">".to_string()),
1918 ];
1919 sugg.extend(visitor.returns.into_iter().flat_map(|expr| {
1920 let span =
1921 expr.span.find_ancestor_in_same_ctxt(obligation.cause.span).unwrap_or(expr.span);
1922 if !span.can_be_used_for_suggestions() {
1923 vec![]
1924 } else if let hir::ExprKind::Call(path, ..) = expr.kind
1925 && let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, method)) = path.kind
1926 && method.ident.name == sym::new
1927 && let hir::TyKind::Path(hir::QPath::Resolved(.., box_path)) = ty.kind
1928 && box_path
1929 .res
1930 .opt_def_id()
1931 .is_some_and(|def_id| self.tcx.is_lang_item(def_id, LangItem::OwnedBox))
1932 {
1933 vec![]
1935 } else {
1936 vec![
1937 (span.shrink_to_lo(), "Box::new(".to_string()),
1938 (span.shrink_to_hi(), ")".to_string()),
1939 ]
1940 }
1941 }));
1942
1943 err.multipart_suggestion(
1944 format!(
1945 "alternatively, box the return type, and wrap all of the returned values in \
1946 `Box::new`",
1947 ),
1948 sugg,
1949 Applicability::MaybeIncorrect,
1950 );
1951
1952 true
1953 }
1954
1955 pub(super) fn report_closure_arg_mismatch(
1956 &self,
1957 span: Span,
1958 found_span: Option<Span>,
1959 found: ty::TraitRef<'tcx>,
1960 expected: ty::TraitRef<'tcx>,
1961 cause: &ObligationCauseCode<'tcx>,
1962 found_node: Option<Node<'_>>,
1963 param_env: ty::ParamEnv<'tcx>,
1964 ) -> Diag<'a> {
1965 pub(crate) fn build_fn_sig_ty<'tcx>(
1966 infcx: &InferCtxt<'tcx>,
1967 trait_ref: ty::TraitRef<'tcx>,
1968 ) -> Ty<'tcx> {
1969 let inputs = trait_ref.args.type_at(1);
1970 let sig = match inputs.kind() {
1971 ty::Tuple(inputs) if infcx.tcx.is_fn_trait(trait_ref.def_id) => {
1972 infcx.tcx.mk_fn_sig(
1973 *inputs,
1974 infcx.next_ty_var(DUMMY_SP),
1975 false,
1976 hir::Safety::Safe,
1977 ExternAbi::Rust,
1978 )
1979 }
1980 _ => infcx.tcx.mk_fn_sig(
1981 [inputs],
1982 infcx.next_ty_var(DUMMY_SP),
1983 false,
1984 hir::Safety::Safe,
1985 ExternAbi::Rust,
1986 ),
1987 };
1988
1989 Ty::new_fn_ptr(infcx.tcx, ty::Binder::dummy(sig))
1990 }
1991
1992 let argument_kind = match expected.self_ty().kind() {
1993 ty::Closure(..) => "closure",
1994 ty::Coroutine(..) => "coroutine",
1995 _ => "function",
1996 };
1997 let mut err = struct_span_code_err!(
1998 self.dcx(),
1999 span,
2000 E0631,
2001 "type mismatch in {argument_kind} arguments",
2002 );
2003
2004 err.span_label(span, "expected due to this");
2005
2006 let found_span = found_span.unwrap_or(span);
2007 err.span_label(found_span, "found signature defined here");
2008
2009 let expected = build_fn_sig_ty(self, expected);
2010 let found = build_fn_sig_ty(self, found);
2011
2012 let (expected_str, found_str) = self.cmp(expected, found);
2013
2014 let signature_kind = format!("{argument_kind} signature");
2015 err.note_expected_found(&signature_kind, expected_str, &signature_kind, found_str);
2016
2017 self.note_conflicting_fn_args(&mut err, cause, expected, found, param_env);
2018 self.note_conflicting_closure_bounds(cause, &mut err);
2019
2020 if let Some(found_node) = found_node {
2021 hint_missing_borrow(self, param_env, span, found, expected, found_node, &mut err);
2022 }
2023
2024 err
2025 }
2026
2027 fn note_conflicting_fn_args(
2028 &self,
2029 err: &mut Diag<'_>,
2030 cause: &ObligationCauseCode<'tcx>,
2031 expected: Ty<'tcx>,
2032 found: Ty<'tcx>,
2033 param_env: ty::ParamEnv<'tcx>,
2034 ) {
2035 let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = cause else {
2036 return;
2037 };
2038 let ty::FnPtr(sig_tys, hdr) = expected.kind() else {
2039 return;
2040 };
2041 let expected = sig_tys.with(*hdr);
2042 let ty::FnPtr(sig_tys, hdr) = found.kind() else {
2043 return;
2044 };
2045 let found = sig_tys.with(*hdr);
2046 let Node::Expr(arg) = self.tcx.hir_node(*arg_hir_id) else {
2047 return;
2048 };
2049 let hir::ExprKind::Path(path) = arg.kind else {
2050 return;
2051 };
2052 let expected_inputs = self.tcx.instantiate_bound_regions_with_erased(expected).inputs();
2053 let found_inputs = self.tcx.instantiate_bound_regions_with_erased(found).inputs();
2054 let both_tys = expected_inputs.iter().copied().zip(found_inputs.iter().copied());
2055
2056 let arg_expr = |infcx: &InferCtxt<'tcx>, name, expected: Ty<'tcx>, found: Ty<'tcx>| {
2057 let (expected_ty, expected_refs) = get_deref_type_and_refs(expected);
2058 let (found_ty, found_refs) = get_deref_type_and_refs(found);
2059
2060 if infcx.can_eq(param_env, found_ty, expected_ty) {
2061 if found_refs.len() == expected_refs.len()
2062 && found_refs.iter().eq(expected_refs.iter())
2063 {
2064 name
2065 } else if found_refs.len() > expected_refs.len() {
2066 let refs = &found_refs[..found_refs.len() - expected_refs.len()];
2067 if found_refs[..expected_refs.len()].iter().eq(expected_refs.iter()) {
2068 format!(
2069 "{}{name}",
2070 refs.iter()
2071 .map(|mutbl| format!("&{}", mutbl.prefix_str()))
2072 .collect::<Vec<_>>()
2073 .join(""),
2074 )
2075 } else {
2076 format!(
2078 "{}*{name}",
2079 refs.iter()
2080 .map(|mutbl| format!("&{}", mutbl.prefix_str()))
2081 .collect::<Vec<_>>()
2082 .join(""),
2083 )
2084 }
2085 } else if expected_refs.len() > found_refs.len() {
2086 format!(
2087 "{}{name}",
2088 (0..(expected_refs.len() - found_refs.len()))
2089 .map(|_| "*")
2090 .collect::<Vec<_>>()
2091 .join(""),
2092 )
2093 } else {
2094 format!(
2095 "{}{name}",
2096 found_refs
2097 .iter()
2098 .map(|mutbl| format!("&{}", mutbl.prefix_str()))
2099 .chain(found_refs.iter().map(|_| "*".to_string()))
2100 .collect::<Vec<_>>()
2101 .join(""),
2102 )
2103 }
2104 } else {
2105 format!("/* {found} */")
2106 }
2107 };
2108 let args_have_same_underlying_type = both_tys.clone().all(|(expected, found)| {
2109 let (expected_ty, _) = get_deref_type_and_refs(expected);
2110 let (found_ty, _) = get_deref_type_and_refs(found);
2111 self.can_eq(param_env, found_ty, expected_ty)
2112 });
2113 let (closure_names, call_names): (Vec<_>, Vec<_>) = if args_have_same_underlying_type
2114 && !expected_inputs.is_empty()
2115 && expected_inputs.len() == found_inputs.len()
2116 && let Some(typeck) = &self.typeck_results
2117 && let Res::Def(res_kind, fn_def_id) = typeck.qpath_res(&path, *arg_hir_id)
2118 && res_kind.is_fn_like()
2119 {
2120 let closure: Vec<_> = self
2121 .tcx
2122 .fn_arg_idents(fn_def_id)
2123 .iter()
2124 .enumerate()
2125 .map(|(i, ident)| {
2126 if let Some(ident) = ident
2127 && !matches!(ident, Ident { name: kw::Underscore | kw::SelfLower, .. })
2128 {
2129 format!("{ident}")
2130 } else {
2131 format!("arg{i}")
2132 }
2133 })
2134 .collect();
2135 let args = closure
2136 .iter()
2137 .zip(both_tys)
2138 .map(|(name, (expected, found))| {
2139 arg_expr(self.infcx, name.to_owned(), expected, found)
2140 })
2141 .collect();
2142 (closure, args)
2143 } else {
2144 let closure_args = expected_inputs
2145 .iter()
2146 .enumerate()
2147 .map(|(i, _)| format!("arg{i}"))
2148 .collect::<Vec<_>>();
2149 let call_args = both_tys
2150 .enumerate()
2151 .map(|(i, (expected, found))| {
2152 arg_expr(self.infcx, format!("arg{i}"), expected, found)
2153 })
2154 .collect::<Vec<_>>();
2155 (closure_args, call_args)
2156 };
2157 let closure_names: Vec<_> = closure_names
2158 .into_iter()
2159 .zip(expected_inputs.iter())
2160 .map(|(name, ty)| {
2161 format!(
2162 "{name}{}",
2163 if ty.has_infer_types() {
2164 String::new()
2165 } else if ty.references_error() {
2166 ": /* type */".to_string()
2167 } else {
2168 format!(": {ty}")
2169 }
2170 )
2171 })
2172 .collect();
2173 err.multipart_suggestion(
2174 "consider wrapping the function in a closure",
2175 vec![
2176 (arg.span.shrink_to_lo(), format!("|{}| ", closure_names.join(", "))),
2177 (arg.span.shrink_to_hi(), format!("({})", call_names.join(", "))),
2178 ],
2179 Applicability::MaybeIncorrect,
2180 );
2181 }
2182
2183 fn note_conflicting_closure_bounds(
2186 &self,
2187 cause: &ObligationCauseCode<'tcx>,
2188 err: &mut Diag<'_>,
2189 ) {
2190 if let ObligationCauseCode::WhereClauseInExpr(def_id, _, _, idx) = cause
2194 && let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx)
2195 && let Some(pred) = predicates.predicates.get(*idx)
2196 && let ty::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder()
2197 && self.tcx.is_fn_trait(trait_pred.def_id())
2198 {
2199 let expected_self =
2200 self.tcx.anonymize_bound_vars(pred.kind().rebind(trait_pred.self_ty()));
2201 let expected_args =
2202 self.tcx.anonymize_bound_vars(pred.kind().rebind(trait_pred.trait_ref.args));
2203
2204 let other_pred = predicates.into_iter().enumerate().find(|(other_idx, (pred, _))| {
2207 match pred.kind().skip_binder() {
2208 ty::ClauseKind::Trait(trait_pred)
2209 if self.tcx.is_fn_trait(trait_pred.def_id())
2210 && other_idx != idx
2211 && expected_self
2214 == self.tcx.anonymize_bound_vars(
2215 pred.kind().rebind(trait_pred.self_ty()),
2216 )
2217 && expected_args
2219 != self.tcx.anonymize_bound_vars(
2220 pred.kind().rebind(trait_pred.trait_ref.args),
2221 ) =>
2222 {
2223 true
2224 }
2225 _ => false,
2226 }
2227 });
2228 if let Some((_, (_, other_pred_span))) = other_pred {
2230 err.span_note(
2231 other_pred_span,
2232 "closure inferred to have a different signature due to this bound",
2233 );
2234 }
2235 }
2236 }
2237
2238 pub(super) fn suggest_fully_qualified_path(
2239 &self,
2240 err: &mut Diag<'_>,
2241 item_def_id: DefId,
2242 span: Span,
2243 trait_ref: DefId,
2244 ) {
2245 if let Some(assoc_item) = self.tcx.opt_associated_item(item_def_id)
2246 && let ty::AssocKind::Const { .. } | ty::AssocKind::Type { .. } = assoc_item.kind
2247 {
2248 err.note(format!(
2249 "{}s cannot be accessed directly on a `trait`, they can only be \
2250 accessed through a specific `impl`",
2251 self.tcx.def_kind_descr(assoc_item.as_def_kind(), item_def_id)
2252 ));
2253
2254 if !assoc_item.is_impl_trait_in_trait() {
2255 err.span_suggestion_verbose(
2256 span,
2257 "use the fully qualified path to an implementation",
2258 format!(
2259 "<Type as {}>::{}",
2260 self.tcx.def_path_str(trait_ref),
2261 assoc_item.name()
2262 ),
2263 Applicability::HasPlaceholders,
2264 );
2265 }
2266 }
2267 }
2268
2269 #[instrument(level = "debug", skip_all, fields(?obligation.predicate, ?obligation.cause.span))]
2312 pub fn maybe_note_obligation_cause_for_async_await<G: EmissionGuarantee>(
2313 &self,
2314 err: &mut Diag<'_, G>,
2315 obligation: &PredicateObligation<'tcx>,
2316 ) -> bool {
2317 let (mut trait_ref, mut target_ty) = match obligation.predicate.kind().skip_binder() {
2340 ty::PredicateKind::Clause(ty::ClauseKind::Trait(p)) => (Some(p), Some(p.self_ty())),
2341 _ => (None, None),
2342 };
2343 let mut coroutine = None;
2344 let mut outer_coroutine = None;
2345 let mut next_code = Some(obligation.cause.code());
2346
2347 let mut seen_upvar_tys_infer_tuple = false;
2348
2349 while let Some(code) = next_code {
2350 debug!(?code);
2351 match code {
2352 ObligationCauseCode::FunctionArg { parent_code, .. } => {
2353 next_code = Some(parent_code);
2354 }
2355 ObligationCauseCode::ImplDerived(cause) => {
2356 let ty = cause.derived.parent_trait_pred.skip_binder().self_ty();
2357 debug!(
2358 parent_trait_ref = ?cause.derived.parent_trait_pred,
2359 self_ty.kind = ?ty.kind(),
2360 "ImplDerived",
2361 );
2362
2363 match *ty.kind() {
2364 ty::Coroutine(did, ..) | ty::CoroutineWitness(did, _) => {
2365 coroutine = coroutine.or(Some(did));
2366 outer_coroutine = Some(did);
2367 }
2368 ty::Tuple(_) if !seen_upvar_tys_infer_tuple => {
2369 seen_upvar_tys_infer_tuple = true;
2374 }
2375 _ if coroutine.is_none() => {
2376 trait_ref = Some(cause.derived.parent_trait_pred.skip_binder());
2377 target_ty = Some(ty);
2378 }
2379 _ => {}
2380 }
2381
2382 next_code = Some(&cause.derived.parent_code);
2383 }
2384 ObligationCauseCode::WellFormedDerived(derived_obligation)
2385 | ObligationCauseCode::BuiltinDerived(derived_obligation) => {
2386 let ty = derived_obligation.parent_trait_pred.skip_binder().self_ty();
2387 debug!(
2388 parent_trait_ref = ?derived_obligation.parent_trait_pred,
2389 self_ty.kind = ?ty.kind(),
2390 );
2391
2392 match *ty.kind() {
2393 ty::Coroutine(did, ..) | ty::CoroutineWitness(did, ..) => {
2394 coroutine = coroutine.or(Some(did));
2395 outer_coroutine = Some(did);
2396 }
2397 ty::Tuple(_) if !seen_upvar_tys_infer_tuple => {
2398 seen_upvar_tys_infer_tuple = true;
2403 }
2404 _ if coroutine.is_none() => {
2405 trait_ref = Some(derived_obligation.parent_trait_pred.skip_binder());
2406 target_ty = Some(ty);
2407 }
2408 _ => {}
2409 }
2410
2411 next_code = Some(&derived_obligation.parent_code);
2412 }
2413 _ => break,
2414 }
2415 }
2416
2417 debug!(?coroutine, ?trait_ref, ?target_ty);
2419 let (Some(coroutine_did), Some(trait_ref), Some(target_ty)) =
2420 (coroutine, trait_ref, target_ty)
2421 else {
2422 return false;
2423 };
2424
2425 let span = self.tcx.def_span(coroutine_did);
2426
2427 let coroutine_did_root = self.tcx.typeck_root_def_id(coroutine_did);
2428 debug!(
2429 ?coroutine_did,
2430 ?coroutine_did_root,
2431 typeck_results.hir_owner = ?self.typeck_results.as_ref().map(|t| t.hir_owner),
2432 ?span,
2433 );
2434
2435 let coroutine_body =
2436 coroutine_did.as_local().and_then(|def_id| self.tcx.hir_maybe_body_owned_by(def_id));
2437 let mut visitor = AwaitsVisitor::default();
2438 if let Some(body) = coroutine_body {
2439 visitor.visit_body(&body);
2440 }
2441 debug!(awaits = ?visitor.awaits);
2442
2443 let target_ty_erased = self.tcx.erase_and_anonymize_regions(target_ty);
2446 let ty_matches = |ty| -> bool {
2447 let ty_erased = self.tcx.instantiate_bound_regions_with_erased(ty);
2460 let ty_erased = self.tcx.erase_and_anonymize_regions(ty_erased);
2461 let eq = ty_erased == target_ty_erased;
2462 debug!(?ty_erased, ?target_ty_erased, ?eq);
2463 eq
2464 };
2465
2466 let coroutine_data = match &self.typeck_results {
2471 Some(t) if t.hir_owner.to_def_id() == coroutine_did_root => CoroutineData(t),
2472 _ if coroutine_did.is_local() => {
2473 CoroutineData(self.tcx.typeck(coroutine_did.expect_local()))
2474 }
2475 _ => return false,
2476 };
2477
2478 let coroutine_within_in_progress_typeck = match &self.typeck_results {
2479 Some(t) => t.hir_owner.to_def_id() == coroutine_did_root,
2480 _ => false,
2481 };
2482
2483 let mut interior_or_upvar_span = None;
2484
2485 let from_awaited_ty = coroutine_data.get_from_await_ty(visitor, self.tcx, ty_matches);
2486 debug!(?from_awaited_ty);
2487
2488 if coroutine_did.is_local()
2490 && !coroutine_within_in_progress_typeck
2492 && let Some(coroutine_info) = self.tcx.mir_coroutine_witnesses(coroutine_did)
2493 {
2494 debug!(?coroutine_info);
2495 'find_source: for (variant, source_info) in
2496 coroutine_info.variant_fields.iter().zip(&coroutine_info.variant_source_info)
2497 {
2498 debug!(?variant);
2499 for &local in variant {
2500 let decl = &coroutine_info.field_tys[local];
2501 debug!(?decl);
2502 if ty_matches(ty::Binder::dummy(decl.ty)) && !decl.ignore_for_traits {
2503 interior_or_upvar_span = Some(CoroutineInteriorOrUpvar::Interior(
2504 decl.source_info.span,
2505 Some((source_info.span, from_awaited_ty)),
2506 ));
2507 break 'find_source;
2508 }
2509 }
2510 }
2511 }
2512
2513 if interior_or_upvar_span.is_none() {
2514 interior_or_upvar_span =
2515 coroutine_data.try_get_upvar_span(self, coroutine_did, ty_matches);
2516 }
2517
2518 if interior_or_upvar_span.is_none() && !coroutine_did.is_local() {
2519 interior_or_upvar_span = Some(CoroutineInteriorOrUpvar::Interior(span, None));
2520 }
2521
2522 debug!(?interior_or_upvar_span);
2523 if let Some(interior_or_upvar_span) = interior_or_upvar_span {
2524 let is_async = self.tcx.coroutine_is_async(coroutine_did);
2525 self.note_obligation_cause_for_async_await(
2526 err,
2527 interior_or_upvar_span,
2528 is_async,
2529 outer_coroutine,
2530 trait_ref,
2531 target_ty,
2532 obligation,
2533 next_code,
2534 );
2535 true
2536 } else {
2537 false
2538 }
2539 }
2540
2541 #[instrument(level = "debug", skip_all)]
2544 fn note_obligation_cause_for_async_await<G: EmissionGuarantee>(
2545 &self,
2546 err: &mut Diag<'_, G>,
2547 interior_or_upvar_span: CoroutineInteriorOrUpvar,
2548 is_async: bool,
2549 outer_coroutine: Option<DefId>,
2550 trait_pred: ty::TraitPredicate<'tcx>,
2551 target_ty: Ty<'tcx>,
2552 obligation: &PredicateObligation<'tcx>,
2553 next_code: Option<&ObligationCauseCode<'tcx>>,
2554 ) {
2555 let source_map = self.tcx.sess.source_map();
2556
2557 let (await_or_yield, an_await_or_yield) =
2558 if is_async { ("await", "an await") } else { ("yield", "a yield") };
2559 let future_or_coroutine = if is_async { "future" } else { "coroutine" };
2560
2561 let trait_explanation = if let Some(name @ (sym::Send | sym::Sync)) =
2564 self.tcx.get_diagnostic_name(trait_pred.def_id())
2565 {
2566 let (trait_name, trait_verb) =
2567 if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") };
2568
2569 err.code = None;
2570 err.primary_message(format!(
2571 "{future_or_coroutine} cannot be {trait_verb} between threads safely"
2572 ));
2573
2574 let original_span = err.span.primary_span().unwrap();
2575 let mut span = MultiSpan::from_span(original_span);
2576
2577 let message = outer_coroutine
2578 .and_then(|coroutine_did| {
2579 Some(match self.tcx.coroutine_kind(coroutine_did).unwrap() {
2580 CoroutineKind::Coroutine(_) => format!("coroutine is not {trait_name}"),
2581 CoroutineKind::Desugared(
2582 CoroutineDesugaring::Async,
2583 CoroutineSource::Fn,
2584 ) => self
2585 .tcx
2586 .parent(coroutine_did)
2587 .as_local()
2588 .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did))
2589 .and_then(|parent_hir_id| self.tcx.hir_opt_name(parent_hir_id))
2590 .map(|name| {
2591 format!("future returned by `{name}` is not {trait_name}")
2592 })?,
2593 CoroutineKind::Desugared(
2594 CoroutineDesugaring::Async,
2595 CoroutineSource::Block,
2596 ) => {
2597 format!("future created by async block is not {trait_name}")
2598 }
2599 CoroutineKind::Desugared(
2600 CoroutineDesugaring::Async,
2601 CoroutineSource::Closure,
2602 ) => {
2603 format!("future created by async closure is not {trait_name}")
2604 }
2605 CoroutineKind::Desugared(
2606 CoroutineDesugaring::AsyncGen,
2607 CoroutineSource::Fn,
2608 ) => self
2609 .tcx
2610 .parent(coroutine_did)
2611 .as_local()
2612 .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did))
2613 .and_then(|parent_hir_id| self.tcx.hir_opt_name(parent_hir_id))
2614 .map(|name| {
2615 format!("async iterator returned by `{name}` is not {trait_name}")
2616 })?,
2617 CoroutineKind::Desugared(
2618 CoroutineDesugaring::AsyncGen,
2619 CoroutineSource::Block,
2620 ) => {
2621 format!("async iterator created by async gen block is not {trait_name}")
2622 }
2623 CoroutineKind::Desugared(
2624 CoroutineDesugaring::AsyncGen,
2625 CoroutineSource::Closure,
2626 ) => {
2627 format!(
2628 "async iterator created by async gen closure is not {trait_name}"
2629 )
2630 }
2631 CoroutineKind::Desugared(CoroutineDesugaring::Gen, CoroutineSource::Fn) => {
2632 self.tcx
2633 .parent(coroutine_did)
2634 .as_local()
2635 .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did))
2636 .and_then(|parent_hir_id| self.tcx.hir_opt_name(parent_hir_id))
2637 .map(|name| {
2638 format!("iterator returned by `{name}` is not {trait_name}")
2639 })?
2640 }
2641 CoroutineKind::Desugared(
2642 CoroutineDesugaring::Gen,
2643 CoroutineSource::Block,
2644 ) => {
2645 format!("iterator created by gen block is not {trait_name}")
2646 }
2647 CoroutineKind::Desugared(
2648 CoroutineDesugaring::Gen,
2649 CoroutineSource::Closure,
2650 ) => {
2651 format!("iterator created by gen closure is not {trait_name}")
2652 }
2653 })
2654 })
2655 .unwrap_or_else(|| format!("{future_or_coroutine} is not {trait_name}"));
2656
2657 span.push_span_label(original_span, message);
2658 err.span(span);
2659
2660 format!("is not {trait_name}")
2661 } else {
2662 format!("does not implement `{}`", trait_pred.print_modifiers_and_trait_path())
2663 };
2664
2665 let mut explain_yield = |interior_span: Span, yield_span: Span| {
2666 let mut span = MultiSpan::from_span(yield_span);
2667 let snippet = match source_map.span_to_snippet(interior_span) {
2668 Ok(snippet) if !snippet.contains('\n') => format!("`{snippet}`"),
2671 _ => "the value".to_string(),
2672 };
2673 span.push_span_label(
2690 yield_span,
2691 format!("{await_or_yield} occurs here, with {snippet} maybe used later"),
2692 );
2693 span.push_span_label(
2694 interior_span,
2695 format!("has type `{target_ty}` which {trait_explanation}"),
2696 );
2697 err.span_note(
2698 span,
2699 format!("{future_or_coroutine} {trait_explanation} as this value is used across {an_await_or_yield}"),
2700 );
2701 };
2702 match interior_or_upvar_span {
2703 CoroutineInteriorOrUpvar::Interior(interior_span, interior_extra_info) => {
2704 if let Some((yield_span, from_awaited_ty)) = interior_extra_info {
2705 if let Some(await_span) = from_awaited_ty {
2706 let mut span = MultiSpan::from_span(await_span);
2708 span.push_span_label(
2709 await_span,
2710 format!(
2711 "await occurs here on type `{target_ty}`, which {trait_explanation}"
2712 ),
2713 );
2714 err.span_note(
2715 span,
2716 format!(
2717 "future {trait_explanation} as it awaits another future which {trait_explanation}"
2718 ),
2719 );
2720 } else {
2721 explain_yield(interior_span, yield_span);
2723 }
2724 }
2725 }
2726 CoroutineInteriorOrUpvar::Upvar(upvar_span) => {
2727 let non_send = match target_ty.kind() {
2729 ty::Ref(_, ref_ty, mutability) => match self.evaluate_obligation(obligation) {
2730 Ok(eval) if !eval.may_apply() => Some((ref_ty, mutability.is_mut())),
2731 _ => None,
2732 },
2733 _ => None,
2734 };
2735
2736 let (span_label, span_note) = match non_send {
2737 Some((ref_ty, is_mut)) => {
2741 let ref_ty_trait = if is_mut { "Send" } else { "Sync" };
2742 let ref_kind = if is_mut { "&mut" } else { "&" };
2743 (
2744 format!(
2745 "has type `{target_ty}` which {trait_explanation}, because `{ref_ty}` is not `{ref_ty_trait}`"
2746 ),
2747 format!(
2748 "captured value {trait_explanation} because `{ref_kind}` references cannot be sent unless their referent is `{ref_ty_trait}`"
2749 ),
2750 )
2751 }
2752 None => (
2753 format!("has type `{target_ty}` which {trait_explanation}"),
2754 format!("captured value {trait_explanation}"),
2755 ),
2756 };
2757
2758 let mut span = MultiSpan::from_span(upvar_span);
2759 span.push_span_label(upvar_span, span_label);
2760 err.span_note(span, span_note);
2761 }
2762 }
2763
2764 debug!(?next_code);
2767 self.note_obligation_cause_code(
2768 obligation.cause.body_id,
2769 err,
2770 obligation.predicate,
2771 obligation.param_env,
2772 next_code.unwrap(),
2773 &mut Vec::new(),
2774 &mut Default::default(),
2775 );
2776 }
2777
2778 pub(super) fn note_obligation_cause_code<G: EmissionGuarantee, T>(
2779 &self,
2780 body_id: LocalDefId,
2781 err: &mut Diag<'_, G>,
2782 predicate: T,
2783 param_env: ty::ParamEnv<'tcx>,
2784 cause_code: &ObligationCauseCode<'tcx>,
2785 obligated_types: &mut Vec<Ty<'tcx>>,
2786 seen_requirements: &mut FxHashSet<DefId>,
2787 ) where
2788 T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
2789 {
2790 let tcx = self.tcx;
2791 let predicate = predicate.upcast(tcx);
2792 let suggest_remove_deref = |err: &mut Diag<'_, G>, expr: &hir::Expr<'_>| {
2793 if let Some(pred) = predicate.as_trait_clause()
2794 && tcx.is_lang_item(pred.def_id(), LangItem::Sized)
2795 && let hir::ExprKind::Unary(hir::UnOp::Deref, inner) = expr.kind
2796 {
2797 err.span_suggestion_verbose(
2798 expr.span.until(inner.span),
2799 "references are always `Sized`, even if they point to unsized data; consider \
2800 not dereferencing the expression",
2801 String::new(),
2802 Applicability::MaybeIncorrect,
2803 );
2804 }
2805 };
2806 match *cause_code {
2807 ObligationCauseCode::ExprAssignable
2808 | ObligationCauseCode::MatchExpressionArm { .. }
2809 | ObligationCauseCode::Pattern { .. }
2810 | ObligationCauseCode::IfExpression { .. }
2811 | ObligationCauseCode::IfExpressionWithNoElse
2812 | ObligationCauseCode::MainFunctionType
2813 | ObligationCauseCode::LangFunctionType(_)
2814 | ObligationCauseCode::IntrinsicType
2815 | ObligationCauseCode::MethodReceiver
2816 | ObligationCauseCode::ReturnNoExpression
2817 | ObligationCauseCode::Misc
2818 | ObligationCauseCode::WellFormed(..)
2819 | ObligationCauseCode::MatchImpl(..)
2820 | ObligationCauseCode::ReturnValue(_)
2821 | ObligationCauseCode::BlockTailExpression(..)
2822 | ObligationCauseCode::AwaitableExpr(_)
2823 | ObligationCauseCode::ForLoopIterator
2824 | ObligationCauseCode::QuestionMark
2825 | ObligationCauseCode::CheckAssociatedTypeBounds { .. }
2826 | ObligationCauseCode::LetElse
2827 | ObligationCauseCode::UnOp { .. }
2828 | ObligationCauseCode::BinOp { .. }
2829 | ObligationCauseCode::AscribeUserTypeProvePredicate(..)
2830 | ObligationCauseCode::AlwaysApplicableImpl
2831 | ObligationCauseCode::ConstParam(_)
2832 | ObligationCauseCode::ReferenceOutlivesReferent(..)
2833 | ObligationCauseCode::ObjectTypeBound(..) => {}
2834 ObligationCauseCode::RustCall => {
2835 if let Some(pred) = predicate.as_trait_clause()
2836 && tcx.is_lang_item(pred.def_id(), LangItem::Sized)
2837 {
2838 err.note("argument required to be sized due to `extern \"rust-call\"` ABI");
2839 }
2840 }
2841 ObligationCauseCode::SliceOrArrayElem => {
2842 err.note("slice and array elements must have `Sized` type");
2843 }
2844 ObligationCauseCode::ArrayLen(array_ty) => {
2845 err.note(format!("the length of array `{array_ty}` must be type `usize`"));
2846 }
2847 ObligationCauseCode::TupleElem => {
2848 err.note("only the last element of a tuple may have a dynamically sized type");
2849 }
2850 ObligationCauseCode::DynCompatible(span) => {
2851 err.multipart_suggestion(
2852 "you might have meant to use `Self` to refer to the implementing type",
2853 vec![(span, "Self".into())],
2854 Applicability::MachineApplicable,
2855 );
2856 }
2857 ObligationCauseCode::WhereClause(item_def_id, span)
2858 | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)
2859 | ObligationCauseCode::HostEffectInExpr(item_def_id, span, ..)
2860 if !span.is_dummy() =>
2861 {
2862 if let ObligationCauseCode::WhereClauseInExpr(_, _, hir_id, pos) = &cause_code {
2863 if let Node::Expr(expr) = tcx.parent_hir_node(*hir_id)
2864 && let hir::ExprKind::Call(_, args) = expr.kind
2865 && let Some(expr) = args.get(*pos)
2866 {
2867 suggest_remove_deref(err, &expr);
2868 } else if let Node::Expr(expr) = self.tcx.hir_node(*hir_id)
2869 && let hir::ExprKind::MethodCall(_, _, args, _) = expr.kind
2870 && let Some(expr) = args.get(*pos)
2871 {
2872 suggest_remove_deref(err, &expr);
2873 }
2874 }
2875 let item_name = tcx.def_path_str(item_def_id);
2876 let short_item_name = with_forced_trimmed_paths!(tcx.def_path_str(item_def_id));
2877 let mut multispan = MultiSpan::from(span);
2878 let sm = tcx.sess.source_map();
2879 if let Some(ident) = tcx.opt_item_ident(item_def_id) {
2880 let same_line =
2881 match (sm.lookup_line(ident.span.hi()), sm.lookup_line(span.lo())) {
2882 (Ok(l), Ok(r)) => l.line == r.line,
2883 _ => true,
2884 };
2885 if ident.span.is_visible(sm) && !ident.span.overlaps(span) && !same_line {
2886 multispan.push_span_label(
2887 ident.span,
2888 format!(
2889 "required by a bound in this {}",
2890 tcx.def_kind(item_def_id).descr(item_def_id)
2891 ),
2892 );
2893 }
2894 }
2895 let mut a = "a";
2896 let mut this = "this bound";
2897 let mut note = None;
2898 let mut help = None;
2899 if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() {
2900 match clause {
2901 ty::ClauseKind::Trait(trait_pred) => {
2902 let def_id = trait_pred.def_id();
2903 let visible_item = if let Some(local) = def_id.as_local() {
2904 let ty = trait_pred.self_ty();
2905 if let ty::Adt(adt, _) = ty.kind() {
2909 let visibilities = &tcx.resolutions(()).effective_visibilities;
2910 visibilities.effective_vis(local).is_none_or(|v| {
2911 v.at_level(Level::Reexported)
2912 .is_accessible_from(adt.did(), tcx)
2913 })
2914 } else {
2915 true
2917 }
2918 } else {
2919 tcx.visible_parent_map(()).get(&def_id).is_some()
2921 };
2922 if tcx.is_lang_item(def_id, LangItem::Sized) {
2923 if tcx
2925 .generics_of(item_def_id)
2926 .own_params
2927 .iter()
2928 .any(|param| tcx.def_span(param.def_id) == span)
2929 {
2930 a = "an implicit `Sized`";
2931 this =
2932 "the implicit `Sized` requirement on this type parameter";
2933 }
2934 if let Some(hir::Node::TraitItem(hir::TraitItem {
2935 generics,
2936 kind: hir::TraitItemKind::Type(bounds, None),
2937 ..
2938 })) = tcx.hir_get_if_local(item_def_id)
2939 && !bounds.iter()
2941 .filter_map(|bound| bound.trait_ref())
2942 .any(|tr| tr.trait_def_id().is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Sized)))
2943 {
2944 let (span, separator) = if let [.., last] = bounds {
2945 (last.span().shrink_to_hi(), " +")
2946 } else {
2947 (generics.span.shrink_to_hi(), ":")
2948 };
2949 err.span_suggestion_verbose(
2950 span,
2951 "consider relaxing the implicit `Sized` restriction",
2952 format!("{separator} ?Sized"),
2953 Applicability::MachineApplicable,
2954 );
2955 }
2956 }
2957 if let DefKind::Trait = tcx.def_kind(item_def_id)
2958 && !visible_item
2959 {
2960 note = Some(format!(
2961 "`{short_item_name}` is a \"sealed trait\", because to implement it \
2962 you also need to implement `{}`, which is not accessible; this is \
2963 usually done to force you to use one of the provided types that \
2964 already implement it",
2965 with_no_trimmed_paths!(tcx.def_path_str(def_id)),
2966 ));
2967 let impls_of = tcx.trait_impls_of(def_id);
2968 let impls = impls_of
2969 .non_blanket_impls()
2970 .values()
2971 .flatten()
2972 .chain(impls_of.blanket_impls().iter())
2973 .collect::<Vec<_>>();
2974 if !impls.is_empty() {
2975 let len = impls.len();
2976 let mut types = impls
2977 .iter()
2978 .map(|t| {
2979 with_no_trimmed_paths!(format!(
2980 " {}",
2981 tcx.type_of(*t).instantiate_identity(),
2982 ))
2983 })
2984 .collect::<Vec<_>>();
2985 let post = if types.len() > 9 {
2986 types.truncate(8);
2987 format!("\nand {} others", len - 8)
2988 } else {
2989 String::new()
2990 };
2991 help = Some(format!(
2992 "the following type{} implement{} the trait:\n{}{post}",
2993 pluralize!(len),
2994 if len == 1 { "s" } else { "" },
2995 types.join("\n"),
2996 ));
2997 }
2998 }
2999 }
3000 ty::ClauseKind::ConstArgHasType(..) => {
3001 let descr =
3002 format!("required by a const generic parameter in `{item_name}`");
3003 if span.is_visible(sm) {
3004 let msg = format!(
3005 "required by this const generic parameter in `{short_item_name}`"
3006 );
3007 multispan.push_span_label(span, msg);
3008 err.span_note(multispan, descr);
3009 } else {
3010 err.span_note(tcx.def_span(item_def_id), descr);
3011 }
3012 return;
3013 }
3014 _ => (),
3015 }
3016 }
3017
3018 let is_in_fmt_lit = if let Some(s) = err.span.primary_span() {
3021 matches!(s.desugaring_kind(), Some(DesugaringKind::FormatLiteral { .. }))
3022 } else {
3023 false
3024 };
3025 if !is_in_fmt_lit {
3026 let descr = format!("required by {a} bound in `{item_name}`");
3027 if span.is_visible(sm) {
3028 let msg = format!("required by {this} in `{short_item_name}`");
3029 multispan.push_span_label(span, msg);
3030 err.span_note(multispan, descr);
3031 } else {
3032 err.span_note(tcx.def_span(item_def_id), descr);
3033 }
3034 }
3035 if let Some(note) = note {
3036 err.note(note);
3037 }
3038 if let Some(help) = help {
3039 err.help(help);
3040 }
3041 }
3042 ObligationCauseCode::WhereClause(..)
3043 | ObligationCauseCode::WhereClauseInExpr(..)
3044 | ObligationCauseCode::HostEffectInExpr(..) => {
3045 }
3048 ObligationCauseCode::OpaqueTypeBound(span, definition_def_id) => {
3049 err.span_note(span, "required by a bound in an opaque type");
3050 if let Some(definition_def_id) = definition_def_id
3051 && self.tcx.typeck(definition_def_id).coroutine_stalled_predicates.is_empty()
3055 {
3056 err.span_note(
3059 tcx.def_span(definition_def_id),
3060 "this definition site has more where clauses than the opaque type",
3061 );
3062 }
3063 }
3064 ObligationCauseCode::Coercion { source, target } => {
3065 let source =
3066 tcx.short_string(self.resolve_vars_if_possible(source), err.long_ty_path());
3067 let target =
3068 tcx.short_string(self.resolve_vars_if_possible(target), err.long_ty_path());
3069 err.note(with_forced_trimmed_paths!(format!(
3070 "required for the cast from `{source}` to `{target}`",
3071 )));
3072 }
3073 ObligationCauseCode::RepeatElementCopy { is_constable, elt_span } => {
3074 err.note(
3075 "the `Copy` trait is required because this value will be copied for each element of the array",
3076 );
3077 let sm = tcx.sess.source_map();
3078 if matches!(is_constable, IsConstable::Fn | IsConstable::Ctor)
3079 && let Ok(_) = sm.span_to_snippet(elt_span)
3080 {
3081 err.multipart_suggestion(
3082 "create an inline `const` block",
3083 vec![
3084 (elt_span.shrink_to_lo(), "const { ".to_string()),
3085 (elt_span.shrink_to_hi(), " }".to_string()),
3086 ],
3087 Applicability::MachineApplicable,
3088 );
3089 } else {
3090 err.help("consider using `core::array::from_fn` to initialize the array");
3092 err.help("see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information");
3093 }
3094 }
3095 ObligationCauseCode::VariableType(hir_id) => {
3096 if let Some(typeck_results) = &self.typeck_results
3097 && let Some(ty) = typeck_results.node_type_opt(hir_id)
3098 && let ty::Error(_) = ty.kind()
3099 {
3100 err.note(format!(
3101 "`{predicate}` isn't satisfied, but the type of this pattern is \
3102 `{{type error}}`",
3103 ));
3104 err.downgrade_to_delayed_bug();
3105 }
3106 let mut local = true;
3107 match tcx.parent_hir_node(hir_id) {
3108 Node::LetStmt(hir::LetStmt { ty: Some(ty), .. }) => {
3109 err.span_suggestion_verbose(
3110 ty.span.shrink_to_lo(),
3111 "consider borrowing here",
3112 "&",
3113 Applicability::MachineApplicable,
3114 );
3115 }
3116 Node::LetStmt(hir::LetStmt {
3117 init: Some(hir::Expr { kind: hir::ExprKind::Index(..), span, .. }),
3118 ..
3119 }) => {
3120 err.span_suggestion_verbose(
3124 span.shrink_to_lo(),
3125 "consider borrowing here",
3126 "&",
3127 Applicability::MachineApplicable,
3128 );
3129 }
3130 Node::LetStmt(hir::LetStmt { init: Some(expr), .. }) => {
3131 suggest_remove_deref(err, &expr);
3134 }
3135 Node::Param(param) => {
3136 err.span_suggestion_verbose(
3137 param.ty_span.shrink_to_lo(),
3138 "function arguments must have a statically known size, borrowed types \
3139 always have a known size",
3140 "&",
3141 Applicability::MachineApplicable,
3142 );
3143 local = false;
3144 }
3145 _ => {}
3146 }
3147 if local {
3148 err.note("all local variables must have a statically known size");
3149 }
3150 }
3151 ObligationCauseCode::SizedArgumentType(hir_id) => {
3152 let mut ty = None;
3153 let borrowed_msg = "function arguments must have a statically known size, borrowed \
3154 types always have a known size";
3155 if let Some(hir_id) = hir_id
3156 && let hir::Node::Param(param) = self.tcx.hir_node(hir_id)
3157 && let Some(decl) = self.tcx.parent_hir_node(hir_id).fn_decl()
3158 && let Some(t) = decl.inputs.iter().find(|t| param.ty_span.contains(t.span))
3159 {
3160 ty = Some(t);
3168 } else if let Some(hir_id) = hir_id
3169 && let hir::Node::Ty(t) = self.tcx.hir_node(hir_id)
3170 {
3171 ty = Some(t);
3172 }
3173 if let Some(ty) = ty {
3174 match ty.kind {
3175 hir::TyKind::TraitObject(traits, _) => {
3176 let (span, kw) = match traits {
3177 [first, ..] if first.span.lo() == ty.span.lo() => {
3178 (ty.span.shrink_to_lo(), "dyn ")
3180 }
3181 [first, ..] => (ty.span.until(first.span), ""),
3182 [] => span_bug!(ty.span, "trait object with no traits: {ty:?}"),
3183 };
3184 let needs_parens = traits.len() != 1;
3185 if let Some(hir_id) = hir_id
3187 && matches!(
3188 self.tcx.parent_hir_node(hir_id),
3189 hir::Node::Item(hir::Item {
3190 kind: hir::ItemKind::Fn { .. },
3191 ..
3192 })
3193 )
3194 {
3195 err.span_suggestion_verbose(
3196 span,
3197 "you can use `impl Trait` as the argument type",
3198 "impl ",
3199 Applicability::MaybeIncorrect,
3200 );
3201 }
3202 let sugg = if !needs_parens {
3203 vec![(span.shrink_to_lo(), format!("&{kw}"))]
3204 } else {
3205 vec![
3206 (span.shrink_to_lo(), format!("&({kw}")),
3207 (ty.span.shrink_to_hi(), ")".to_string()),
3208 ]
3209 };
3210 err.multipart_suggestion_verbose(
3211 borrowed_msg,
3212 sugg,
3213 Applicability::MachineApplicable,
3214 );
3215 }
3216 hir::TyKind::Slice(_ty) => {
3217 err.span_suggestion_verbose(
3218 ty.span.shrink_to_lo(),
3219 "function arguments must have a statically known size, borrowed \
3220 slices always have a known size",
3221 "&",
3222 Applicability::MachineApplicable,
3223 );
3224 }
3225 hir::TyKind::Path(_) => {
3226 err.span_suggestion_verbose(
3227 ty.span.shrink_to_lo(),
3228 borrowed_msg,
3229 "&",
3230 Applicability::MachineApplicable,
3231 );
3232 }
3233 _ => {}
3234 }
3235 } else {
3236 err.note("all function arguments must have a statically known size");
3237 }
3238 if tcx.sess.opts.unstable_features.is_nightly_build()
3239 && !tcx.features().unsized_fn_params()
3240 {
3241 err.help("unsized fn params are gated as an unstable feature");
3242 }
3243 }
3244 ObligationCauseCode::SizedReturnType | ObligationCauseCode::SizedCallReturnType => {
3245 err.note("the return type of a function must have a statically known size");
3246 }
3247 ObligationCauseCode::SizedYieldType => {
3248 err.note("the yield type of a coroutine must have a statically known size");
3249 }
3250 ObligationCauseCode::AssignmentLhsSized => {
3251 err.note("the left-hand-side of an assignment must have a statically known size");
3252 }
3253 ObligationCauseCode::TupleInitializerSized => {
3254 err.note("tuples must have a statically known size to be initialized");
3255 }
3256 ObligationCauseCode::StructInitializerSized => {
3257 err.note("structs must have a statically known size to be initialized");
3258 }
3259 ObligationCauseCode::FieldSized { adt_kind: ref item, last, span } => {
3260 match *item {
3261 AdtKind::Struct => {
3262 if last {
3263 err.note(
3264 "the last field of a packed struct may only have a \
3265 dynamically sized type if it does not need drop to be run",
3266 );
3267 } else {
3268 err.note(
3269 "only the last field of a struct may have a dynamically sized type",
3270 );
3271 }
3272 }
3273 AdtKind::Union => {
3274 err.note("no field of a union may have a dynamically sized type");
3275 }
3276 AdtKind::Enum => {
3277 err.note("no field of an enum variant may have a dynamically sized type");
3278 }
3279 }
3280 err.help("change the field's type to have a statically known size");
3281 err.span_suggestion_verbose(
3282 span.shrink_to_lo(),
3283 "borrowed types always have a statically known size",
3284 "&",
3285 Applicability::MachineApplicable,
3286 );
3287 err.multipart_suggestion_verbose(
3288 "the `Box` type always has a statically known size and allocates its contents \
3289 in the heap",
3290 vec![
3291 (span.shrink_to_lo(), "Box<".to_string()),
3292 (span.shrink_to_hi(), ">".to_string()),
3293 ],
3294 Applicability::MachineApplicable,
3295 );
3296 }
3297 ObligationCauseCode::SizedConstOrStatic => {
3298 err.note("statics and constants must have a statically known size");
3299 }
3300 ObligationCauseCode::InlineAsmSized => {
3301 err.note("all inline asm arguments must have a statically known size");
3302 }
3303 ObligationCauseCode::SizedClosureCapture(closure_def_id) => {
3304 err.note(
3305 "all values captured by value by a closure must have a statically known size",
3306 );
3307 let hir::ExprKind::Closure(closure) =
3308 tcx.hir_node_by_def_id(closure_def_id).expect_expr().kind
3309 else {
3310 bug!("expected closure in SizedClosureCapture obligation");
3311 };
3312 if let hir::CaptureBy::Value { .. } = closure.capture_clause
3313 && let Some(span) = closure.fn_arg_span
3314 {
3315 err.span_label(span, "this closure captures all values by move");
3316 }
3317 }
3318 ObligationCauseCode::SizedCoroutineInterior(coroutine_def_id) => {
3319 let what = match tcx.coroutine_kind(coroutine_def_id) {
3320 None
3321 | Some(hir::CoroutineKind::Coroutine(_))
3322 | Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => {
3323 "yield"
3324 }
3325 Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
3326 "await"
3327 }
3328 Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => {
3329 "yield`/`await"
3330 }
3331 };
3332 err.note(format!(
3333 "all values live across `{what}` must have a statically known size"
3334 ));
3335 }
3336 ObligationCauseCode::SharedStatic => {
3337 err.note("shared static variables must have a type that implements `Sync`");
3338 }
3339 ObligationCauseCode::BuiltinDerived(ref data) => {
3340 let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
3341 let ty = parent_trait_ref.skip_binder().self_ty();
3342 if parent_trait_ref.references_error() {
3343 err.downgrade_to_delayed_bug();
3346 return;
3347 }
3348
3349 let is_upvar_tys_infer_tuple = if !matches!(ty.kind(), ty::Tuple(..)) {
3352 false
3353 } else if let ObligationCauseCode::BuiltinDerived(data) = &*data.parent_code {
3354 let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
3355 let nested_ty = parent_trait_ref.skip_binder().self_ty();
3356 matches!(nested_ty.kind(), ty::Coroutine(..))
3357 || matches!(nested_ty.kind(), ty::Closure(..))
3358 } else {
3359 false
3360 };
3361
3362 let is_builtin_async_fn_trait =
3363 tcx.async_fn_trait_kind_from_def_id(data.parent_trait_pred.def_id()).is_some();
3364
3365 if !is_upvar_tys_infer_tuple && !is_builtin_async_fn_trait {
3366 let mut msg = || {
3367 let ty_str = tcx.short_string(ty, err.long_ty_path());
3368 format!("required because it appears within the type `{ty_str}`")
3369 };
3370 match ty.kind() {
3371 ty::Adt(def, _) => {
3372 let msg = msg();
3373 match tcx.opt_item_ident(def.did()) {
3374 Some(ident) => {
3375 err.span_note(ident.span, msg);
3376 }
3377 None => {
3378 err.note(msg);
3379 }
3380 }
3381 }
3382 ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
3383 let is_future = tcx.ty_is_opaque_future(ty);
3386 debug!(
3387 ?obligated_types,
3388 ?is_future,
3389 "note_obligation_cause_code: check for async fn"
3390 );
3391 if is_future
3392 && obligated_types.last().is_some_and(|ty| match ty.kind() {
3393 ty::Coroutine(last_def_id, ..) => {
3394 tcx.coroutine_is_async(*last_def_id)
3395 }
3396 _ => false,
3397 })
3398 {
3399 } else {
3401 let msg = msg();
3402 err.span_note(tcx.def_span(def_id), msg);
3403 }
3404 }
3405 ty::Coroutine(def_id, _) => {
3406 let sp = tcx.def_span(def_id);
3407
3408 let kind = tcx.coroutine_kind(def_id).unwrap();
3410 err.span_note(
3411 sp,
3412 with_forced_trimmed_paths!(format!(
3413 "required because it's used within this {kind:#}",
3414 )),
3415 );
3416 }
3417 ty::CoroutineWitness(..) => {
3418 }
3421 ty::Closure(def_id, _) | ty::CoroutineClosure(def_id, _) => {
3422 err.span_note(
3423 tcx.def_span(def_id),
3424 "required because it's used within this closure",
3425 );
3426 }
3427 ty::Str => {
3428 err.note("`str` is considered to contain a `[u8]` slice for auto trait purposes");
3429 }
3430 _ => {
3431 let msg = msg();
3432 err.note(msg);
3433 }
3434 };
3435 }
3436
3437 obligated_types.push(ty);
3438
3439 let parent_predicate = parent_trait_ref;
3440 if !self.is_recursive_obligation(obligated_types, &data.parent_code) {
3441 ensure_sufficient_stack(|| {
3443 self.note_obligation_cause_code(
3444 body_id,
3445 err,
3446 parent_predicate,
3447 param_env,
3448 &data.parent_code,
3449 obligated_types,
3450 seen_requirements,
3451 )
3452 });
3453 } else {
3454 ensure_sufficient_stack(|| {
3455 self.note_obligation_cause_code(
3456 body_id,
3457 err,
3458 parent_predicate,
3459 param_env,
3460 cause_code.peel_derives(),
3461 obligated_types,
3462 seen_requirements,
3463 )
3464 });
3465 }
3466 }
3467 ObligationCauseCode::ImplDerived(ref data) => {
3468 let mut parent_trait_pred =
3469 self.resolve_vars_if_possible(data.derived.parent_trait_pred);
3470 let parent_def_id = parent_trait_pred.def_id();
3471 if tcx.is_diagnostic_item(sym::FromResidual, parent_def_id)
3472 && !tcx.features().enabled(sym::try_trait_v2)
3473 {
3474 return;
3478 }
3479 let self_ty_str =
3480 tcx.short_string(parent_trait_pred.skip_binder().self_ty(), err.long_ty_path());
3481 let trait_name = tcx.short_string(
3482 parent_trait_pred.print_modifiers_and_trait_path(),
3483 err.long_ty_path(),
3484 );
3485 let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`");
3486 let mut is_auto_trait = false;
3487 match tcx.hir_get_if_local(data.impl_or_alias_def_id) {
3488 Some(Node::Item(hir::Item {
3489 kind: hir::ItemKind::Trait(_, is_auto, _, ident, ..),
3490 ..
3491 })) => {
3492 is_auto_trait = matches!(is_auto, hir::IsAuto::Yes);
3495 err.span_note(ident.span, msg);
3496 }
3497 Some(Node::Item(hir::Item {
3498 kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, generics, .. }),
3499 ..
3500 })) => {
3501 let mut spans = Vec::with_capacity(2);
3502 if let Some(of_trait) = of_trait {
3503 spans.push(of_trait.trait_ref.path.span);
3504 }
3505 spans.push(self_ty.span);
3506 let mut spans: MultiSpan = spans.into();
3507 if matches!(
3508 self_ty.span.ctxt().outer_expn_data().kind,
3509 ExpnKind::Macro(MacroKind::Derive, _)
3510 ) || matches!(
3511 of_trait.map(|t| t.trait_ref.path.span.ctxt().outer_expn_data().kind),
3512 Some(ExpnKind::Macro(MacroKind::Derive, _))
3513 ) {
3514 spans.push_span_label(
3515 data.span,
3516 "unsatisfied trait bound introduced in this `derive` macro",
3517 );
3518 } else if !data.span.is_dummy() && !data.span.overlaps(self_ty.span) {
3519 spans.push_span_label(
3520 data.span,
3521 "unsatisfied trait bound introduced here",
3522 );
3523 }
3524 err.span_note(spans, msg);
3525 point_at_assoc_type_restriction(
3526 tcx,
3527 err,
3528 &self_ty_str,
3529 &trait_name,
3530 predicate,
3531 &generics,
3532 &data,
3533 );
3534 }
3535 _ => {
3536 err.note(msg);
3537 }
3538 };
3539
3540 let mut parent_predicate = parent_trait_pred;
3541 let mut data = &data.derived;
3542 let mut count = 0;
3543 seen_requirements.insert(parent_def_id);
3544 if is_auto_trait {
3545 while let ObligationCauseCode::BuiltinDerived(derived) = &*data.parent_code {
3548 let child_trait_ref =
3549 self.resolve_vars_if_possible(derived.parent_trait_pred);
3550 let child_def_id = child_trait_ref.def_id();
3551 if seen_requirements.insert(child_def_id) {
3552 break;
3553 }
3554 data = derived;
3555 parent_predicate = child_trait_ref.upcast(tcx);
3556 parent_trait_pred = child_trait_ref;
3557 }
3558 }
3559 while let ObligationCauseCode::ImplDerived(child) = &*data.parent_code {
3560 let child_trait_pred =
3562 self.resolve_vars_if_possible(child.derived.parent_trait_pred);
3563 let child_def_id = child_trait_pred.def_id();
3564 if seen_requirements.insert(child_def_id) {
3565 break;
3566 }
3567 count += 1;
3568 data = &child.derived;
3569 parent_predicate = child_trait_pred.upcast(tcx);
3570 parent_trait_pred = child_trait_pred;
3571 }
3572 if count > 0 {
3573 err.note(format!(
3574 "{} redundant requirement{} hidden",
3575 count,
3576 pluralize!(count)
3577 ));
3578 let self_ty = tcx.short_string(
3579 parent_trait_pred.skip_binder().self_ty(),
3580 err.long_ty_path(),
3581 );
3582 let trait_path = tcx.short_string(
3583 parent_trait_pred.print_modifiers_and_trait_path(),
3584 err.long_ty_path(),
3585 );
3586 err.note(format!("required for `{self_ty}` to implement `{trait_path}`"));
3587 }
3588 ensure_sufficient_stack(|| {
3590 self.note_obligation_cause_code(
3591 body_id,
3592 err,
3593 parent_predicate,
3594 param_env,
3595 &data.parent_code,
3596 obligated_types,
3597 seen_requirements,
3598 )
3599 });
3600 }
3601 ObligationCauseCode::ImplDerivedHost(ref data) => {
3602 let self_ty = tcx.short_string(
3603 self.resolve_vars_if_possible(data.derived.parent_host_pred.self_ty()),
3604 err.long_ty_path(),
3605 );
3606 let trait_path = tcx.short_string(
3607 data.derived
3608 .parent_host_pred
3609 .map_bound(|pred| pred.trait_ref)
3610 .print_only_trait_path(),
3611 err.long_ty_path(),
3612 );
3613 let msg = format!(
3614 "required for `{self_ty}` to implement `{} {trait_path}`",
3615 data.derived.parent_host_pred.skip_binder().constness,
3616 );
3617 match tcx.hir_get_if_local(data.impl_def_id) {
3618 Some(Node::Item(hir::Item {
3619 kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
3620 ..
3621 })) => {
3622 let mut spans = vec![self_ty.span];
3623 spans.extend(of_trait.map(|t| t.trait_ref.path.span));
3624 let mut spans: MultiSpan = spans.into();
3625 spans.push_span_label(data.span, "unsatisfied trait bound introduced here");
3626 err.span_note(spans, msg);
3627 }
3628 _ => {
3629 err.note(msg);
3630 }
3631 }
3632 ensure_sufficient_stack(|| {
3633 self.note_obligation_cause_code(
3634 body_id,
3635 err,
3636 data.derived.parent_host_pred,
3637 param_env,
3638 &data.derived.parent_code,
3639 obligated_types,
3640 seen_requirements,
3641 )
3642 });
3643 }
3644 ObligationCauseCode::BuiltinDerivedHost(ref data) => {
3645 ensure_sufficient_stack(|| {
3646 self.note_obligation_cause_code(
3647 body_id,
3648 err,
3649 data.parent_host_pred,
3650 param_env,
3651 &data.parent_code,
3652 obligated_types,
3653 seen_requirements,
3654 )
3655 });
3656 }
3657 ObligationCauseCode::WellFormedDerived(ref data) => {
3658 let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
3659 let parent_predicate = parent_trait_ref;
3660 ensure_sufficient_stack(|| {
3662 self.note_obligation_cause_code(
3663 body_id,
3664 err,
3665 parent_predicate,
3666 param_env,
3667 &data.parent_code,
3668 obligated_types,
3669 seen_requirements,
3670 )
3671 });
3672 }
3673 ObligationCauseCode::TypeAlias(ref nested, span, def_id) => {
3674 ensure_sufficient_stack(|| {
3676 self.note_obligation_cause_code(
3677 body_id,
3678 err,
3679 predicate,
3680 param_env,
3681 nested,
3682 obligated_types,
3683 seen_requirements,
3684 )
3685 });
3686 let mut multispan = MultiSpan::from(span);
3687 multispan.push_span_label(span, "required by this bound");
3688 err.span_note(
3689 multispan,
3690 format!("required by a bound on the type alias `{}`", tcx.item_name(def_id)),
3691 );
3692 }
3693 ObligationCauseCode::FunctionArg {
3694 arg_hir_id, call_hir_id, ref parent_code, ..
3695 } => {
3696 self.note_function_argument_obligation(
3697 body_id,
3698 err,
3699 arg_hir_id,
3700 parent_code,
3701 param_env,
3702 predicate,
3703 call_hir_id,
3704 );
3705 ensure_sufficient_stack(|| {
3706 self.note_obligation_cause_code(
3707 body_id,
3708 err,
3709 predicate,
3710 param_env,
3711 parent_code,
3712 obligated_types,
3713 seen_requirements,
3714 )
3715 });
3716 }
3717 ObligationCauseCode::CompareImplItem { trait_item_def_id, .. }
3720 if tcx.is_impl_trait_in_trait(trait_item_def_id) => {}
3721 ObligationCauseCode::CompareImplItem { trait_item_def_id, kind, .. } => {
3722 let item_name = tcx.item_name(trait_item_def_id);
3723 let msg = format!(
3724 "the requirement `{predicate}` appears on the `impl`'s {kind} \
3725 `{item_name}` but not on the corresponding trait's {kind}",
3726 );
3727 let sp = tcx
3728 .opt_item_ident(trait_item_def_id)
3729 .map(|i| i.span)
3730 .unwrap_or_else(|| tcx.def_span(trait_item_def_id));
3731 let mut assoc_span: MultiSpan = sp.into();
3732 assoc_span.push_span_label(
3733 sp,
3734 format!("this trait's {kind} doesn't have the requirement `{predicate}`"),
3735 );
3736 if let Some(ident) = tcx
3737 .opt_associated_item(trait_item_def_id)
3738 .and_then(|i| tcx.opt_item_ident(i.container_id(tcx)))
3739 {
3740 assoc_span.push_span_label(ident.span, "in this trait");
3741 }
3742 err.span_note(assoc_span, msg);
3743 }
3744 ObligationCauseCode::TrivialBound => {
3745 err.help("see issue #48214");
3746 tcx.disabled_nightly_features(err, [(String::new(), sym::trivial_bounds)]);
3747 }
3748 ObligationCauseCode::OpaqueReturnType(expr_info) => {
3749 let (expr_ty, expr) = if let Some((expr_ty, hir_id)) = expr_info {
3750 let expr_ty = tcx.short_string(expr_ty, err.long_ty_path());
3751 let expr = tcx.hir_expect_expr(hir_id);
3752 (expr_ty, expr)
3753 } else if let Some(body_id) = tcx.hir_node_by_def_id(body_id).body_id()
3754 && let body = tcx.hir_body(body_id)
3755 && let hir::ExprKind::Block(block, _) = body.value.kind
3756 && let Some(expr) = block.expr
3757 && let Some(expr_ty) = self
3758 .typeck_results
3759 .as_ref()
3760 .and_then(|typeck| typeck.node_type_opt(expr.hir_id))
3761 && let Some(pred) = predicate.as_clause()
3762 && let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder()
3763 && self.can_eq(param_env, pred.self_ty(), expr_ty)
3764 {
3765 let expr_ty = tcx.short_string(expr_ty, err.long_ty_path());
3766 (expr_ty, expr)
3767 } else {
3768 return;
3769 };
3770 err.span_label(
3771 expr.span,
3772 with_forced_trimmed_paths!(format!(
3773 "return type was inferred to be `{expr_ty}` here",
3774 )),
3775 );
3776 suggest_remove_deref(err, &expr);
3777 }
3778 ObligationCauseCode::UnsizedNonPlaceExpr(span) => {
3779 err.span_note(
3780 span,
3781 "unsized values must be place expressions and cannot be put in temporaries",
3782 );
3783 }
3784 }
3785 }
3786
3787 #[instrument(
3788 level = "debug", skip(self, err), fields(trait_pred.self_ty = ?trait_pred.self_ty())
3789 )]
3790 pub(super) fn suggest_await_before_try(
3791 &self,
3792 err: &mut Diag<'_>,
3793 obligation: &PredicateObligation<'tcx>,
3794 trait_pred: ty::PolyTraitPredicate<'tcx>,
3795 span: Span,
3796 ) {
3797 let future_trait = self.tcx.require_lang_item(LangItem::Future, span);
3798
3799 let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
3800 let impls_future = self.type_implements_trait(
3801 future_trait,
3802 [self.tcx.instantiate_bound_regions_with_erased(self_ty)],
3803 obligation.param_env,
3804 );
3805 if !impls_future.must_apply_modulo_regions() {
3806 return;
3807 }
3808
3809 let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
3810 let projection_ty = trait_pred.map_bound(|trait_pred| {
3812 Ty::new_projection(
3813 self.tcx,
3814 item_def_id,
3815 [trait_pred.self_ty()],
3817 )
3818 });
3819 let InferOk { value: projection_ty, .. } =
3820 self.at(&obligation.cause, obligation.param_env).normalize(projection_ty);
3821
3822 debug!(
3823 normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty)
3824 );
3825 let try_obligation = self.mk_trait_obligation_with_new_self_ty(
3826 obligation.param_env,
3827 trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())),
3828 );
3829 debug!(try_trait_obligation = ?try_obligation);
3830 if self.predicate_may_hold(&try_obligation)
3831 && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
3832 && snippet.ends_with('?')
3833 {
3834 match self.tcx.coroutine_kind(obligation.cause.body_id) {
3835 Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
3836 err.span_suggestion_verbose(
3837 span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(),
3838 "consider `await`ing on the `Future`",
3839 ".await",
3840 Applicability::MaybeIncorrect,
3841 );
3842 }
3843 _ => {
3844 let mut span: MultiSpan = span.with_lo(span.hi() - BytePos(1)).into();
3845 span.push_span_label(
3846 self.tcx.def_span(obligation.cause.body_id),
3847 "this is not `async`",
3848 );
3849 err.span_note(
3850 span,
3851 "this implements `Future` and its output type supports \
3852 `?`, but the future cannot be awaited in a synchronous function",
3853 );
3854 }
3855 }
3856 }
3857 }
3858
3859 pub(super) fn suggest_floating_point_literal(
3860 &self,
3861 obligation: &PredicateObligation<'tcx>,
3862 err: &mut Diag<'_>,
3863 trait_pred: ty::PolyTraitPredicate<'tcx>,
3864 ) {
3865 let rhs_span = match obligation.cause.code() {
3866 ObligationCauseCode::BinOp { rhs_span, rhs_is_lit, .. } if *rhs_is_lit => rhs_span,
3867 _ => return,
3868 };
3869 if let ty::Float(_) = trait_pred.skip_binder().self_ty().kind()
3870 && let ty::Infer(InferTy::IntVar(_)) =
3871 trait_pred.skip_binder().trait_ref.args.type_at(1).kind()
3872 {
3873 err.span_suggestion_verbose(
3874 rhs_span.shrink_to_hi(),
3875 "consider using a floating-point literal by writing it with `.0`",
3876 ".0",
3877 Applicability::MaybeIncorrect,
3878 );
3879 }
3880 }
3881
3882 pub fn can_suggest_derive(
3883 &self,
3884 obligation: &PredicateObligation<'tcx>,
3885 trait_pred: ty::PolyTraitPredicate<'tcx>,
3886 ) -> bool {
3887 if trait_pred.polarity() == ty::PredicatePolarity::Negative {
3888 return false;
3889 }
3890 let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) else {
3891 return false;
3892 };
3893 let (adt, args) = match trait_pred.skip_binder().self_ty().kind() {
3894 ty::Adt(adt, args) if adt.did().is_local() => (adt, args),
3895 _ => return false,
3896 };
3897 let is_derivable_trait = match diagnostic_name {
3898 sym::Default => !adt.is_enum(),
3899 sym::PartialEq | sym::PartialOrd => {
3900 let rhs_ty = trait_pred.skip_binder().trait_ref.args.type_at(1);
3901 trait_pred.skip_binder().self_ty() == rhs_ty
3902 }
3903 sym::Eq | sym::Ord | sym::Clone | sym::Copy | sym::Hash | sym::Debug => true,
3904 _ => false,
3905 };
3906 is_derivable_trait &&
3907 adt.all_fields().all(|field| {
3909 let field_ty = ty::GenericArg::from(field.ty(self.tcx, args));
3910 let trait_args = match diagnostic_name {
3911 sym::PartialEq | sym::PartialOrd => {
3912 Some(field_ty)
3913 }
3914 _ => None,
3915 };
3916 let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate {
3917 trait_ref: ty::TraitRef::new(self.tcx,
3918 trait_pred.def_id(),
3919 [field_ty].into_iter().chain(trait_args),
3920 ),
3921 ..*tr
3922 });
3923 let field_obl = Obligation::new(
3924 self.tcx,
3925 obligation.cause.clone(),
3926 obligation.param_env,
3927 trait_pred,
3928 );
3929 self.predicate_must_hold_modulo_regions(&field_obl)
3930 })
3931 }
3932
3933 pub fn suggest_derive(
3934 &self,
3935 obligation: &PredicateObligation<'tcx>,
3936 err: &mut Diag<'_>,
3937 trait_pred: ty::PolyTraitPredicate<'tcx>,
3938 ) {
3939 let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) else {
3940 return;
3941 };
3942 let adt = match trait_pred.skip_binder().self_ty().kind() {
3943 ty::Adt(adt, _) if adt.did().is_local() => adt,
3944 _ => return,
3945 };
3946 if self.can_suggest_derive(obligation, trait_pred) {
3947 err.span_suggestion_verbose(
3948 self.tcx.def_span(adt.did()).shrink_to_lo(),
3949 format!(
3950 "consider annotating `{}` with `#[derive({})]`",
3951 trait_pred.skip_binder().self_ty(),
3952 diagnostic_name,
3953 ),
3954 format!("#[derive({diagnostic_name})]\n"),
3956 Applicability::MaybeIncorrect,
3957 );
3958 }
3959 }
3960
3961 pub(super) fn suggest_dereferencing_index(
3962 &self,
3963 obligation: &PredicateObligation<'tcx>,
3964 err: &mut Diag<'_>,
3965 trait_pred: ty::PolyTraitPredicate<'tcx>,
3966 ) {
3967 if let ObligationCauseCode::ImplDerived(_) = obligation.cause.code()
3968 && self
3969 .tcx
3970 .is_diagnostic_item(sym::SliceIndex, trait_pred.skip_binder().trait_ref.def_id)
3971 && let ty::Slice(_) = trait_pred.skip_binder().trait_ref.args.type_at(1).kind()
3972 && let ty::Ref(_, inner_ty, _) = trait_pred.skip_binder().self_ty().kind()
3973 && let ty::Uint(ty::UintTy::Usize) = inner_ty.kind()
3974 {
3975 err.span_suggestion_verbose(
3976 obligation.cause.span.shrink_to_lo(),
3977 "dereference this index",
3978 '*',
3979 Applicability::MachineApplicable,
3980 );
3981 }
3982 }
3983
3984 fn note_function_argument_obligation<G: EmissionGuarantee>(
3985 &self,
3986 body_id: LocalDefId,
3987 err: &mut Diag<'_, G>,
3988 arg_hir_id: HirId,
3989 parent_code: &ObligationCauseCode<'tcx>,
3990 param_env: ty::ParamEnv<'tcx>,
3991 failed_pred: ty::Predicate<'tcx>,
3992 call_hir_id: HirId,
3993 ) {
3994 let tcx = self.tcx;
3995 if let Node::Expr(expr) = tcx.hir_node(arg_hir_id)
3996 && let Some(typeck_results) = &self.typeck_results
3997 {
3998 if let hir::Expr { kind: hir::ExprKind::MethodCall(_, rcvr, _, _), .. } = expr
3999 && let Some(ty) = typeck_results.node_type_opt(rcvr.hir_id)
4000 && let Some(failed_pred) = failed_pred.as_trait_clause()
4001 && let pred = failed_pred.map_bound(|pred| pred.with_replaced_self_ty(tcx, ty))
4002 && self.predicate_must_hold_modulo_regions(&Obligation::misc(
4003 tcx, expr.span, body_id, param_env, pred,
4004 ))
4005 && expr.span.hi() != rcvr.span.hi()
4006 {
4007 err.span_suggestion_verbose(
4008 expr.span.with_lo(rcvr.span.hi()),
4009 format!(
4010 "consider removing this method call, as the receiver has type `{ty}` and \
4011 `{pred}` trivially holds",
4012 ),
4013 "",
4014 Applicability::MaybeIncorrect,
4015 );
4016 }
4017 if let hir::Expr { kind: hir::ExprKind::Block(block, _), .. } = expr {
4018 let inner_expr = expr.peel_blocks();
4019 let ty = typeck_results
4020 .expr_ty_adjusted_opt(inner_expr)
4021 .unwrap_or(Ty::new_misc_error(tcx));
4022 let span = inner_expr.span;
4023 if Some(span) != err.span.primary_span()
4024 && !span.in_external_macro(tcx.sess.source_map())
4025 {
4026 err.span_label(
4027 span,
4028 if ty.references_error() {
4029 String::new()
4030 } else {
4031 let ty = with_forced_trimmed_paths!(self.ty_to_string(ty));
4032 format!("this tail expression is of type `{ty}`")
4033 },
4034 );
4035 if let ty::PredicateKind::Clause(clause) = failed_pred.kind().skip_binder()
4036 && let ty::ClauseKind::Trait(pred) = clause
4037 && tcx.fn_trait_kind_from_def_id(pred.def_id()).is_some()
4038 {
4039 if let [stmt, ..] = block.stmts
4040 && let hir::StmtKind::Semi(value) = stmt.kind
4041 && let hir::ExprKind::Closure(hir::Closure {
4042 body, fn_decl_span, ..
4043 }) = value.kind
4044 && let body = tcx.hir_body(*body)
4045 && !matches!(body.value.kind, hir::ExprKind::Block(..))
4046 {
4047 err.multipart_suggestion(
4050 "you might have meant to open the closure body instead of placing \
4051 a closure within a block",
4052 vec![
4053 (expr.span.with_hi(value.span.lo()), String::new()),
4054 (fn_decl_span.shrink_to_hi(), " {".to_string()),
4055 ],
4056 Applicability::MaybeIncorrect,
4057 );
4058 } else {
4059 err.span_suggestion_verbose(
4061 expr.span.shrink_to_lo(),
4062 "you might have meant to create the closure instead of a block",
4063 format!(
4064 "|{}| ",
4065 (0..pred.trait_ref.args.len() - 1)
4066 .map(|_| "_")
4067 .collect::<Vec<_>>()
4068 .join(", ")
4069 ),
4070 Applicability::MaybeIncorrect,
4071 );
4072 }
4073 }
4074 }
4075 }
4076
4077 let mut type_diffs = vec![];
4082 if let ObligationCauseCode::WhereClauseInExpr(def_id, _, _, idx) = parent_code
4083 && let Some(node_args) = typeck_results.node_args_opt(call_hir_id)
4084 && let where_clauses =
4085 self.tcx.predicates_of(def_id).instantiate(self.tcx, node_args)
4086 && let Some(where_pred) = where_clauses.predicates.get(*idx)
4087 {
4088 if let Some(where_pred) = where_pred.as_trait_clause()
4089 && let Some(failed_pred) = failed_pred.as_trait_clause()
4090 && where_pred.def_id() == failed_pred.def_id()
4091 {
4092 self.enter_forall(where_pred, |where_pred| {
4093 let failed_pred = self.instantiate_binder_with_fresh_vars(
4094 expr.span,
4095 BoundRegionConversionTime::FnCall,
4096 failed_pred,
4097 );
4098
4099 let zipped =
4100 iter::zip(where_pred.trait_ref.args, failed_pred.trait_ref.args);
4101 for (expected, actual) in zipped {
4102 self.probe(|_| {
4103 match self
4104 .at(&ObligationCause::misc(expr.span, body_id), param_env)
4105 .eq(DefineOpaqueTypes::Yes, expected, actual)
4108 {
4109 Ok(_) => (), Err(err) => type_diffs.push(err),
4111 }
4112 })
4113 }
4114 })
4115 } else if let Some(where_pred) = where_pred.as_projection_clause()
4116 && let Some(failed_pred) = failed_pred.as_projection_clause()
4117 && let Some(found) = failed_pred.skip_binder().term.as_type()
4118 {
4119 type_diffs = vec![TypeError::Sorts(ty::error::ExpectedFound {
4120 expected: where_pred
4121 .skip_binder()
4122 .projection_term
4123 .expect_ty(self.tcx)
4124 .to_ty(self.tcx),
4125 found,
4126 })];
4127 }
4128 }
4129 if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
4130 && let hir::Path { res: Res::Local(hir_id), .. } = path
4131 && let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id)
4132 && let hir::Node::LetStmt(local) = self.tcx.parent_hir_node(binding.hir_id)
4133 && let Some(binding_expr) = local.init
4134 {
4135 self.point_at_chain(binding_expr, typeck_results, type_diffs, param_env, err);
4139 } else {
4140 self.point_at_chain(expr, typeck_results, type_diffs, param_env, err);
4141 }
4142 }
4143 let call_node = tcx.hir_node(call_hir_id);
4144 if let Node::Expr(hir::Expr { kind: hir::ExprKind::MethodCall(path, rcvr, ..), .. }) =
4145 call_node
4146 {
4147 if Some(rcvr.span) == err.span.primary_span() {
4148 err.replace_span_with(path.ident.span, true);
4149 }
4150 }
4151
4152 if let Node::Expr(expr) = call_node {
4153 if let hir::ExprKind::Call(hir::Expr { span, .. }, _)
4154 | hir::ExprKind::MethodCall(
4155 hir::PathSegment { ident: Ident { span, .. }, .. },
4156 ..,
4157 ) = expr.kind
4158 {
4159 if Some(*span) != err.span.primary_span() {
4160 let msg = if span.is_desugaring(DesugaringKind::FormatLiteral { source: true })
4161 {
4162 "required by this formatting parameter"
4163 } else if span.is_desugaring(DesugaringKind::FormatLiteral { source: false }) {
4164 "required by a formatting parameter in this expression"
4165 } else {
4166 "required by a bound introduced by this call"
4167 };
4168 err.span_label(*span, msg);
4169 }
4170 }
4171
4172 if let hir::ExprKind::MethodCall(_, expr, ..) = expr.kind {
4173 self.suggest_option_method_if_applicable(failed_pred, param_env, err, expr);
4174 }
4175 }
4176 }
4177
4178 fn suggest_option_method_if_applicable<G: EmissionGuarantee>(
4179 &self,
4180 failed_pred: ty::Predicate<'tcx>,
4181 param_env: ty::ParamEnv<'tcx>,
4182 err: &mut Diag<'_, G>,
4183 expr: &hir::Expr<'_>,
4184 ) {
4185 let tcx = self.tcx;
4186 let infcx = self.infcx;
4187 let Some(typeck_results) = self.typeck_results.as_ref() else { return };
4188
4189 let Some(option_ty_adt) = typeck_results.expr_ty_adjusted(expr).ty_adt_def() else {
4191 return;
4192 };
4193 if !tcx.is_diagnostic_item(sym::Option, option_ty_adt.did()) {
4194 return;
4195 }
4196
4197 if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, .. }))
4200 = failed_pred.kind().skip_binder()
4201 && tcx.is_fn_trait(trait_ref.def_id)
4202 && let [self_ty, found_ty] = trait_ref.args.as_slice()
4203 && let Some(fn_ty) = self_ty.as_type().filter(|ty| ty.is_fn())
4204 && let fn_sig @ ty::FnSig {
4205 abi: ExternAbi::Rust,
4206 c_variadic: false,
4207 safety: hir::Safety::Safe,
4208 ..
4209 } = fn_ty.fn_sig(tcx).skip_binder()
4210
4211 && let Some(&ty::Ref(_, target_ty, needs_mut)) = fn_sig.inputs().first().map(|t| t.kind())
4213 && !target_ty.has_escaping_bound_vars()
4214
4215 && let Some(ty::Tuple(tys)) = found_ty.as_type().map(Ty::kind)
4217 && let &[found_ty] = tys.as_slice()
4218 && !found_ty.has_escaping_bound_vars()
4219
4220 && let Some(deref_target_did) = tcx.lang_items().deref_target()
4222 && let projection = Ty::new_projection_from_args(tcx,deref_target_did, tcx.mk_args(&[ty::GenericArg::from(found_ty)]))
4223 && let InferOk { value: deref_target, obligations } = infcx.at(&ObligationCause::dummy(), param_env).normalize(projection)
4224 && obligations.iter().all(|obligation| infcx.predicate_must_hold_modulo_regions(obligation))
4225 && infcx.can_eq(param_env, deref_target, target_ty)
4226 {
4227 let help = if let hir::Mutability::Mut = needs_mut
4228 && let Some(deref_mut_did) = tcx.lang_items().deref_mut_trait()
4229 && infcx
4230 .type_implements_trait(deref_mut_did, iter::once(found_ty), param_env)
4231 .must_apply_modulo_regions()
4232 {
4233 Some(("call `Option::as_deref_mut()` first", ".as_deref_mut()"))
4234 } else if let hir::Mutability::Not = needs_mut {
4235 Some(("call `Option::as_deref()` first", ".as_deref()"))
4236 } else {
4237 None
4238 };
4239
4240 if let Some((msg, sugg)) = help {
4241 err.span_suggestion_with_style(
4242 expr.span.shrink_to_hi(),
4243 msg,
4244 sugg,
4245 Applicability::MaybeIncorrect,
4246 SuggestionStyle::ShowAlways,
4247 );
4248 }
4249 }
4250 }
4251
4252 fn look_for_iterator_item_mistakes<G: EmissionGuarantee>(
4253 &self,
4254 assocs_in_this_method: &[Option<(Span, (DefId, Ty<'tcx>))>],
4255 typeck_results: &TypeckResults<'tcx>,
4256 type_diffs: &[TypeError<'tcx>],
4257 param_env: ty::ParamEnv<'tcx>,
4258 path_segment: &hir::PathSegment<'_>,
4259 args: &[hir::Expr<'_>],
4260 err: &mut Diag<'_, G>,
4261 ) {
4262 let tcx = self.tcx;
4263 for entry in assocs_in_this_method {
4266 let Some((_span, (def_id, ty))) = entry else {
4267 continue;
4268 };
4269 for diff in type_diffs {
4270 let TypeError::Sorts(expected_found) = diff else {
4271 continue;
4272 };
4273 if tcx.is_diagnostic_item(sym::IteratorItem, *def_id)
4274 && path_segment.ident.name == sym::map
4275 && self.can_eq(param_env, expected_found.found, *ty)
4276 && let [arg] = args
4277 && let hir::ExprKind::Closure(closure) = arg.kind
4278 {
4279 let body = tcx.hir_body(closure.body);
4280 if let hir::ExprKind::Block(block, None) = body.value.kind
4281 && let None = block.expr
4282 && let [.., stmt] = block.stmts
4283 && let hir::StmtKind::Semi(expr) = stmt.kind
4284 && expected_found.found.is_unit()
4288 && expr.span.hi() != stmt.span.hi()
4293 {
4294 err.span_suggestion_verbose(
4295 expr.span.shrink_to_hi().with_hi(stmt.span.hi()),
4296 "consider removing this semicolon",
4297 String::new(),
4298 Applicability::MachineApplicable,
4299 );
4300 }
4301 let expr = if let hir::ExprKind::Block(block, None) = body.value.kind
4302 && let Some(expr) = block.expr
4303 {
4304 expr
4305 } else {
4306 body.value
4307 };
4308 if let hir::ExprKind::MethodCall(path_segment, rcvr, [], span) = expr.kind
4309 && path_segment.ident.name == sym::clone
4310 && let Some(expr_ty) = typeck_results.expr_ty_opt(expr)
4311 && let Some(rcvr_ty) = typeck_results.expr_ty_opt(rcvr)
4312 && self.can_eq(param_env, expr_ty, rcvr_ty)
4313 && let ty::Ref(_, ty, _) = expr_ty.kind()
4314 {
4315 err.span_label(
4316 span,
4317 format!(
4318 "this method call is cloning the reference `{expr_ty}`, not \
4319 `{ty}` which doesn't implement `Clone`",
4320 ),
4321 );
4322 let ty::Param(..) = ty.kind() else {
4323 continue;
4324 };
4325 let node =
4326 tcx.hir_node_by_def_id(tcx.hir_get_parent_item(expr.hir_id).def_id);
4327
4328 let pred = ty::Binder::dummy(ty::TraitPredicate {
4329 trait_ref: ty::TraitRef::new(
4330 tcx,
4331 tcx.require_lang_item(LangItem::Clone, span),
4332 [*ty],
4333 ),
4334 polarity: ty::PredicatePolarity::Positive,
4335 });
4336 let Some(generics) = node.generics() else {
4337 continue;
4338 };
4339 let Some(body_id) = node.body_id() else {
4340 continue;
4341 };
4342 suggest_restriction(
4343 tcx,
4344 tcx.hir_body_owner_def_id(body_id),
4345 generics,
4346 &format!("type parameter `{ty}`"),
4347 err,
4348 node.fn_sig(),
4349 None,
4350 pred,
4351 None,
4352 );
4353 }
4354 }
4355 }
4356 }
4357 }
4358
4359 fn point_at_chain<G: EmissionGuarantee>(
4360 &self,
4361 expr: &hir::Expr<'_>,
4362 typeck_results: &TypeckResults<'tcx>,
4363 type_diffs: Vec<TypeError<'tcx>>,
4364 param_env: ty::ParamEnv<'tcx>,
4365 err: &mut Diag<'_, G>,
4366 ) {
4367 let mut primary_spans = vec![];
4368 let mut span_labels = vec![];
4369
4370 let tcx = self.tcx;
4371
4372 let mut print_root_expr = true;
4373 let mut assocs = vec![];
4374 let mut expr = expr;
4375 let mut prev_ty = self.resolve_vars_if_possible(
4376 typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
4377 );
4378 while let hir::ExprKind::MethodCall(path_segment, rcvr_expr, args, span) = expr.kind {
4379 expr = rcvr_expr;
4383 let assocs_in_this_method =
4384 self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env);
4385 self.look_for_iterator_item_mistakes(
4386 &assocs_in_this_method,
4387 typeck_results,
4388 &type_diffs,
4389 param_env,
4390 path_segment,
4391 args,
4392 err,
4393 );
4394 assocs.push(assocs_in_this_method);
4395 prev_ty = self.resolve_vars_if_possible(
4396 typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
4397 );
4398
4399 if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
4400 && let hir::Path { res: Res::Local(hir_id), .. } = path
4401 && let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id)
4402 {
4403 let parent = self.tcx.parent_hir_node(binding.hir_id);
4404 if let hir::Node::LetStmt(local) = parent
4406 && let Some(binding_expr) = local.init
4407 {
4408 expr = binding_expr;
4410 }
4411 if let hir::Node::Param(param) = parent {
4412 let prev_ty = self.resolve_vars_if_possible(
4414 typeck_results
4415 .node_type_opt(param.hir_id)
4416 .unwrap_or(Ty::new_misc_error(tcx)),
4417 );
4418 let assocs_in_this_method = self.probe_assoc_types_at_expr(
4419 &type_diffs,
4420 param.ty_span,
4421 prev_ty,
4422 param.hir_id,
4423 param_env,
4424 );
4425 if assocs_in_this_method.iter().any(|a| a.is_some()) {
4426 assocs.push(assocs_in_this_method);
4427 print_root_expr = false;
4428 }
4429 break;
4430 }
4431 }
4432 }
4433 if let Some(ty) = typeck_results.expr_ty_opt(expr)
4436 && print_root_expr
4437 {
4438 let ty = with_forced_trimmed_paths!(self.ty_to_string(ty));
4439 span_labels.push((expr.span, format!("this expression has type `{ty}`")));
4443 };
4444 let mut assocs = assocs.into_iter().peekable();
4447 while let Some(assocs_in_method) = assocs.next() {
4448 let Some(prev_assoc_in_method) = assocs.peek() else {
4449 for entry in assocs_in_method {
4450 let Some((span, (assoc, ty))) = entry else {
4451 continue;
4452 };
4453 if primary_spans.is_empty()
4454 || type_diffs.iter().any(|diff| {
4455 let TypeError::Sorts(expected_found) = diff else {
4456 return false;
4457 };
4458 self.can_eq(param_env, expected_found.found, ty)
4459 })
4460 {
4461 primary_spans.push(span);
4467 }
4468 span_labels.push((
4469 span,
4470 with_forced_trimmed_paths!(format!(
4471 "`{}` is `{ty}` here",
4472 self.tcx.def_path_str(assoc),
4473 )),
4474 ));
4475 }
4476 break;
4477 };
4478 for (entry, prev_entry) in
4479 assocs_in_method.into_iter().zip(prev_assoc_in_method.into_iter())
4480 {
4481 match (entry, prev_entry) {
4482 (Some((span, (assoc, ty))), Some((_, (_, prev_ty)))) => {
4483 let ty_str = with_forced_trimmed_paths!(self.ty_to_string(ty));
4484
4485 let assoc = with_forced_trimmed_paths!(self.tcx.def_path_str(assoc));
4486 if !self.can_eq(param_env, ty, *prev_ty) {
4487 if type_diffs.iter().any(|diff| {
4488 let TypeError::Sorts(expected_found) = diff else {
4489 return false;
4490 };
4491 self.can_eq(param_env, expected_found.found, ty)
4492 }) {
4493 primary_spans.push(span);
4494 }
4495 span_labels
4496 .push((span, format!("`{assoc}` changed to `{ty_str}` here")));
4497 } else {
4498 span_labels.push((span, format!("`{assoc}` remains `{ty_str}` here")));
4499 }
4500 }
4501 (Some((span, (assoc, ty))), None) => {
4502 span_labels.push((
4503 span,
4504 with_forced_trimmed_paths!(format!(
4505 "`{}` is `{}` here",
4506 self.tcx.def_path_str(assoc),
4507 self.ty_to_string(ty),
4508 )),
4509 ));
4510 }
4511 (None, Some(_)) | (None, None) => {}
4512 }
4513 }
4514 }
4515 if !primary_spans.is_empty() {
4516 let mut multi_span: MultiSpan = primary_spans.into();
4517 for (span, label) in span_labels {
4518 multi_span.push_span_label(span, label);
4519 }
4520 err.span_note(
4521 multi_span,
4522 "the method call chain might not have had the expected associated types",
4523 );
4524 }
4525 }
4526
4527 fn probe_assoc_types_at_expr(
4528 &self,
4529 type_diffs: &[TypeError<'tcx>],
4530 span: Span,
4531 prev_ty: Ty<'tcx>,
4532 body_id: HirId,
4533 param_env: ty::ParamEnv<'tcx>,
4534 ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>> {
4535 let ocx = ObligationCtxt::new(self.infcx);
4536 let mut assocs_in_this_method = Vec::with_capacity(type_diffs.len());
4537 for diff in type_diffs {
4538 let TypeError::Sorts(expected_found) = diff else {
4539 continue;
4540 };
4541 let ty::Alias(ty::Projection, proj) = expected_found.expected.kind() else {
4542 continue;
4543 };
4544
4545 let args = GenericArgs::for_item(self.tcx, proj.def_id, |param, _| {
4549 if param.index == 0 {
4550 debug_assert_matches!(param.kind, ty::GenericParamDefKind::Type { .. });
4551 return prev_ty.into();
4552 }
4553 self.var_for_def(span, param)
4554 });
4555 let ty = self.infcx.next_ty_var(span);
4559 let projection = ty::Binder::dummy(ty::PredicateKind::Clause(
4561 ty::ClauseKind::Projection(ty::ProjectionPredicate {
4562 projection_term: ty::AliasTerm::new_from_args(self.tcx, proj.def_id, args),
4563 term: ty.into(),
4564 }),
4565 ));
4566 let body_def_id = self.tcx.hir_enclosing_body_owner(body_id);
4567 ocx.register_obligation(Obligation::misc(
4569 self.tcx,
4570 span,
4571 body_def_id,
4572 param_env,
4573 projection,
4574 ));
4575 if ocx.select_where_possible().is_empty()
4576 && let ty = self.resolve_vars_if_possible(ty)
4577 && !ty.is_ty_var()
4578 {
4579 assocs_in_this_method.push(Some((span, (proj.def_id, ty))));
4580 } else {
4581 assocs_in_this_method.push(None);
4586 }
4587 }
4588 assocs_in_this_method
4589 }
4590
4591 pub(super) fn suggest_convert_to_slice(
4595 &self,
4596 err: &mut Diag<'_>,
4597 obligation: &PredicateObligation<'tcx>,
4598 trait_pred: ty::PolyTraitPredicate<'tcx>,
4599 candidate_impls: &[ImplCandidate<'tcx>],
4600 span: Span,
4601 ) {
4602 let (ObligationCauseCode::BinOp { .. } | ObligationCauseCode::FunctionArg { .. }) =
4605 obligation.cause.code()
4606 else {
4607 return;
4608 };
4609
4610 let (element_ty, mut mutability) = match *trait_pred.skip_binder().self_ty().kind() {
4615 ty::Array(element_ty, _) => (element_ty, None),
4616
4617 ty::Ref(_, pointee_ty, mutability) => match *pointee_ty.kind() {
4618 ty::Array(element_ty, _) => (element_ty, Some(mutability)),
4619 _ => return,
4620 },
4621
4622 _ => return,
4623 };
4624
4625 let mut is_slice = |candidate: Ty<'tcx>| match *candidate.kind() {
4628 ty::RawPtr(t, m) | ty::Ref(_, t, m) => {
4629 if matches!(*t.kind(), ty::Slice(e) if e == element_ty)
4630 && m == mutability.unwrap_or(m)
4631 {
4632 mutability = Some(m);
4634 true
4635 } else {
4636 false
4637 }
4638 }
4639 _ => false,
4640 };
4641
4642 if let Some(slice_ty) = candidate_impls
4644 .iter()
4645 .map(|trait_ref| trait_ref.trait_ref.self_ty())
4646 .find(|t| is_slice(*t))
4647 {
4648 let msg = format!("convert the array to a `{slice_ty}` slice instead");
4649
4650 if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
4651 let mut suggestions = vec![];
4652 if snippet.starts_with('&') {
4653 } else if let Some(hir::Mutability::Mut) = mutability {
4654 suggestions.push((span.shrink_to_lo(), "&mut ".into()));
4655 } else {
4656 suggestions.push((span.shrink_to_lo(), "&".into()));
4657 }
4658 suggestions.push((span.shrink_to_hi(), "[..]".into()));
4659 err.multipart_suggestion_verbose(msg, suggestions, Applicability::MaybeIncorrect);
4660 } else {
4661 err.span_help(span, msg);
4662 }
4663 }
4664 }
4665
4666 pub(super) fn suggest_tuple_wrapping(
4671 &self,
4672 err: &mut Diag<'_>,
4673 root_obligation: &PredicateObligation<'tcx>,
4674 obligation: &PredicateObligation<'tcx>,
4675 ) {
4676 let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code() else {
4677 return;
4678 };
4679
4680 let Some(root_pred) = root_obligation.predicate.as_trait_clause() else { return };
4681
4682 let trait_ref = root_pred.map_bound(|root_pred| {
4683 root_pred.trait_ref.with_replaced_self_ty(
4684 self.tcx,
4685 Ty::new_tup(self.tcx, &[root_pred.trait_ref.self_ty()]),
4686 )
4687 });
4688
4689 let obligation =
4690 Obligation::new(self.tcx, obligation.cause.clone(), obligation.param_env, trait_ref);
4691
4692 if self.predicate_must_hold_modulo_regions(&obligation) {
4693 let arg_span = self.tcx.hir_span(*arg_hir_id);
4694 err.multipart_suggestion_verbose(
4695 format!("use a unary tuple instead"),
4696 vec![(arg_span.shrink_to_lo(), "(".into()), (arg_span.shrink_to_hi(), ",)".into())],
4697 Applicability::MaybeIncorrect,
4698 );
4699 }
4700 }
4701
4702 pub(super) fn explain_hrtb_projection(
4703 &self,
4704 diag: &mut Diag<'_>,
4705 pred: ty::PolyTraitPredicate<'tcx>,
4706 param_env: ty::ParamEnv<'tcx>,
4707 cause: &ObligationCause<'tcx>,
4708 ) {
4709 if pred.skip_binder().has_escaping_bound_vars() && pred.skip_binder().has_non_region_infer()
4710 {
4711 self.probe(|_| {
4712 let ocx = ObligationCtxt::new(self);
4713 self.enter_forall(pred, |pred| {
4714 let pred = ocx.normalize(&ObligationCause::dummy(), param_env, pred);
4715 ocx.register_obligation(Obligation::new(
4716 self.tcx,
4717 ObligationCause::dummy(),
4718 param_env,
4719 pred,
4720 ));
4721 });
4722 if !ocx.select_where_possible().is_empty() {
4723 return;
4725 }
4726
4727 if let ObligationCauseCode::FunctionArg {
4728 call_hir_id,
4729 arg_hir_id,
4730 parent_code: _,
4731 } = cause.code()
4732 {
4733 let arg_span = self.tcx.hir_span(*arg_hir_id);
4734 let mut sp: MultiSpan = arg_span.into();
4735
4736 sp.push_span_label(
4737 arg_span,
4738 "the trait solver is unable to infer the \
4739 generic types that should be inferred from this argument",
4740 );
4741 sp.push_span_label(
4742 self.tcx.hir_span(*call_hir_id),
4743 "add turbofish arguments to this call to \
4744 specify the types manually, even if it's redundant",
4745 );
4746 diag.span_note(
4747 sp,
4748 "this is a known limitation of the trait solver that \
4749 will be lifted in the future",
4750 );
4751 } else {
4752 let mut sp: MultiSpan = cause.span.into();
4753 sp.push_span_label(
4754 cause.span,
4755 "try adding turbofish arguments to this expression to \
4756 specify the types manually, even if it's redundant",
4757 );
4758 diag.span_note(
4759 sp,
4760 "this is a known limitation of the trait solver that \
4761 will be lifted in the future",
4762 );
4763 }
4764 });
4765 }
4766 }
4767
4768 pub(super) fn suggest_desugaring_async_fn_in_trait(
4769 &self,
4770 err: &mut Diag<'_>,
4771 trait_pred: ty::PolyTraitPredicate<'tcx>,
4772 ) {
4773 if self.tcx.features().return_type_notation() {
4775 return;
4776 }
4777
4778 let trait_def_id = trait_pred.def_id();
4779
4780 if !self.tcx.trait_is_auto(trait_def_id) {
4782 return;
4783 }
4784
4785 let ty::Alias(ty::Projection, alias_ty) = trait_pred.self_ty().skip_binder().kind() else {
4787 return;
4788 };
4789 let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) =
4790 self.tcx.opt_rpitit_info(alias_ty.def_id)
4791 else {
4792 return;
4793 };
4794
4795 let auto_trait = self.tcx.def_path_str(trait_def_id);
4796 let Some(fn_def_id) = fn_def_id.as_local() else {
4798 if self.tcx.asyncness(fn_def_id).is_async() {
4800 err.span_note(
4801 self.tcx.def_span(fn_def_id),
4802 format!(
4803 "`{}::{}` is an `async fn` in trait, which does not \
4804 automatically imply that its future is `{auto_trait}`",
4805 alias_ty.trait_ref(self.tcx),
4806 self.tcx.item_name(fn_def_id)
4807 ),
4808 );
4809 }
4810 return;
4811 };
4812 let hir::Node::TraitItem(item) = self.tcx.hir_node_by_def_id(fn_def_id) else {
4813 return;
4814 };
4815
4816 let (sig, body) = item.expect_fn();
4818 let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(opaq_def, ..), .. }) =
4819 sig.decl.output
4820 else {
4821 return;
4823 };
4824
4825 if opaq_def.def_id.to_def_id() != opaque_def_id {
4828 return;
4829 }
4830
4831 let Some(sugg) = suggest_desugaring_async_fn_to_impl_future_in_trait(
4832 self.tcx,
4833 *sig,
4834 *body,
4835 opaque_def_id.expect_local(),
4836 &format!(" + {auto_trait}"),
4837 ) else {
4838 return;
4839 };
4840
4841 let function_name = self.tcx.def_path_str(fn_def_id);
4842 err.multipart_suggestion(
4843 format!(
4844 "`{auto_trait}` can be made part of the associated future's \
4845 guarantees for all implementations of `{function_name}`"
4846 ),
4847 sugg,
4848 Applicability::MachineApplicable,
4849 );
4850 }
4851
4852 pub fn ty_kind_suggestion(
4853 &self,
4854 param_env: ty::ParamEnv<'tcx>,
4855 ty: Ty<'tcx>,
4856 ) -> Option<String> {
4857 let tcx = self.infcx.tcx;
4858 let implements_default = |ty| {
4859 let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
4860 return false;
4861 };
4862 self.type_implements_trait(default_trait, [ty], param_env).must_apply_modulo_regions()
4863 };
4864
4865 Some(match *ty.kind() {
4866 ty::Never | ty::Error(_) => return None,
4867 ty::Bool => "false".to_string(),
4868 ty::Char => "\'x\'".to_string(),
4869 ty::Int(_) | ty::Uint(_) => "42".into(),
4870 ty::Float(_) => "3.14159".into(),
4871 ty::Slice(_) => "[]".to_string(),
4872 ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => {
4873 "vec![]".to_string()
4874 }
4875 ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::String) => {
4876 "String::new()".to_string()
4877 }
4878 ty::Adt(def, args) if def.is_box() => {
4879 format!("Box::new({})", self.ty_kind_suggestion(param_env, args[0].expect_ty())?)
4880 }
4881 ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Option) => {
4882 "None".to_string()
4883 }
4884 ty::Adt(def, args) if Some(def.did()) == tcx.get_diagnostic_item(sym::Result) => {
4885 format!("Ok({})", self.ty_kind_suggestion(param_env, args[0].expect_ty())?)
4886 }
4887 ty::Adt(_, _) if implements_default(ty) => "Default::default()".to_string(),
4888 ty::Ref(_, ty, mutability) => {
4889 if let (ty::Str, hir::Mutability::Not) = (ty.kind(), mutability) {
4890 "\"\"".to_string()
4891 } else {
4892 let ty = self.ty_kind_suggestion(param_env, ty)?;
4893 format!("&{}{ty}", mutability.prefix_str())
4894 }
4895 }
4896 ty::Array(ty, len) if let Some(len) = len.try_to_target_usize(tcx) => {
4897 if len == 0 {
4898 "[]".to_string()
4899 } else if self.type_is_copy_modulo_regions(param_env, ty) || len == 1 {
4900 format!("[{}; {}]", self.ty_kind_suggestion(param_env, ty)?, len)
4902 } else {
4903 "/* value */".to_string()
4904 }
4905 }
4906 ty::Tuple(tys) => format!(
4907 "({}{})",
4908 tys.iter()
4909 .map(|ty| self.ty_kind_suggestion(param_env, ty))
4910 .collect::<Option<Vec<String>>>()?
4911 .join(", "),
4912 if tys.len() == 1 { "," } else { "" }
4913 ),
4914 _ => "/* value */".to_string(),
4915 })
4916 }
4917
4918 pub(super) fn suggest_add_result_as_return_type(
4922 &self,
4923 obligation: &PredicateObligation<'tcx>,
4924 err: &mut Diag<'_>,
4925 trait_pred: ty::PolyTraitPredicate<'tcx>,
4926 ) {
4927 if ObligationCauseCode::QuestionMark != *obligation.cause.code().peel_derives() {
4928 return;
4929 }
4930
4931 fn choose_suggest_items<'tcx, 'hir>(
4938 tcx: TyCtxt<'tcx>,
4939 node: hir::Node<'hir>,
4940 ) -> Option<(&'hir hir::FnDecl<'hir>, hir::BodyId)> {
4941 match node {
4942 hir::Node::Item(item)
4943 if let hir::ItemKind::Fn { sig, body: body_id, .. } = item.kind =>
4944 {
4945 Some((sig.decl, body_id))
4946 }
4947 hir::Node::ImplItem(item)
4948 if let hir::ImplItemKind::Fn(sig, body_id) = item.kind =>
4949 {
4950 let parent = tcx.parent_hir_node(item.hir_id());
4951 if let hir::Node::Item(item) = parent
4952 && let hir::ItemKind::Impl(imp) = item.kind
4953 && imp.of_trait.is_none()
4954 {
4955 return Some((sig.decl, body_id));
4956 }
4957 None
4958 }
4959 _ => None,
4960 }
4961 }
4962
4963 let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id);
4964 if let Some((fn_decl, body_id)) = choose_suggest_items(self.tcx, node)
4965 && let hir::FnRetTy::DefaultReturn(ret_span) = fn_decl.output
4966 && self.tcx.is_diagnostic_item(sym::FromResidual, trait_pred.def_id())
4967 && trait_pred.skip_binder().trait_ref.args.type_at(0).is_unit()
4968 && let ty::Adt(def, _) = trait_pred.skip_binder().trait_ref.args.type_at(1).kind()
4969 && self.tcx.is_diagnostic_item(sym::Result, def.did())
4970 {
4971 let mut sugg_spans =
4972 vec![(ret_span, " -> Result<(), Box<dyn std::error::Error>>".to_string())];
4973 let body = self.tcx.hir_body(body_id);
4974 if let hir::ExprKind::Block(b, _) = body.value.kind
4975 && b.expr.is_none()
4976 {
4977 let span = self.tcx.sess.source_map().end_point(b.span);
4979 sugg_spans.push((
4980 span.shrink_to_lo(),
4981 format!(
4982 "{}{}",
4983 " Ok(())\n",
4984 self.tcx.sess.source_map().indentation_before(span).unwrap_or_default(),
4985 ),
4986 ));
4987 }
4988 err.multipart_suggestion_verbose(
4989 format!("consider adding return type"),
4990 sugg_spans,
4991 Applicability::MaybeIncorrect,
4992 );
4993 }
4994 }
4995
4996 #[instrument(level = "debug", skip_all)]
4997 pub(super) fn suggest_unsized_bound_if_applicable(
4998 &self,
4999 err: &mut Diag<'_>,
5000 obligation: &PredicateObligation<'tcx>,
5001 ) {
5002 let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
5003 obligation.predicate.kind().skip_binder()
5004 else {
5005 return;
5006 };
5007 let (ObligationCauseCode::WhereClause(item_def_id, span)
5008 | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)) =
5009 *obligation.cause.code().peel_derives()
5010 else {
5011 return;
5012 };
5013 if span.is_dummy() {
5014 return;
5015 }
5016 debug!(?pred, ?item_def_id, ?span);
5017
5018 let (Some(node), true) = (
5019 self.tcx.hir_get_if_local(item_def_id),
5020 self.tcx.is_lang_item(pred.def_id(), LangItem::Sized),
5021 ) else {
5022 return;
5023 };
5024
5025 let Some(generics) = node.generics() else {
5026 return;
5027 };
5028 let sized_trait = self.tcx.lang_items().sized_trait();
5029 debug!(?generics.params);
5030 debug!(?generics.predicates);
5031 let Some(param) = generics.params.iter().find(|param| param.span == span) else {
5032 return;
5033 };
5034 let explicitly_sized = generics
5037 .bounds_for_param(param.def_id)
5038 .flat_map(|bp| bp.bounds)
5039 .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait);
5040 if explicitly_sized {
5041 return;
5042 }
5043 debug!(?param);
5044 match node {
5045 hir::Node::Item(
5046 item @ hir::Item {
5047 kind:
5049 hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..),
5050 ..
5051 },
5052 ) => {
5053 if self.suggest_indirection_for_unsized(err, item, param) {
5054 return;
5055 }
5056 }
5057 _ => {}
5058 };
5059
5060 let (span, separator, open_paren_sp) =
5062 if let Some((s, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) {
5063 (s, " +", open_paren_sp)
5064 } else {
5065 (param.name.ident().span.shrink_to_hi(), ":", None)
5066 };
5067
5068 let mut suggs = vec![];
5069 let suggestion = format!("{separator} ?Sized");
5070
5071 if let Some(open_paren_sp) = open_paren_sp {
5072 suggs.push((open_paren_sp, "(".to_string()));
5073 suggs.push((span, format!("){suggestion}")));
5074 } else {
5075 suggs.push((span, suggestion));
5076 }
5077
5078 err.multipart_suggestion_verbose(
5079 "consider relaxing the implicit `Sized` restriction",
5080 suggs,
5081 Applicability::MachineApplicable,
5082 );
5083 }
5084
5085 fn suggest_indirection_for_unsized(
5086 &self,
5087 err: &mut Diag<'_>,
5088 item: &hir::Item<'tcx>,
5089 param: &hir::GenericParam<'tcx>,
5090 ) -> bool {
5091 let mut visitor = FindTypeParam { param: param.name.ident().name, .. };
5095 visitor.visit_item(item);
5096 if visitor.invalid_spans.is_empty() {
5097 return false;
5098 }
5099 let mut multispan: MultiSpan = param.span.into();
5100 multispan.push_span_label(
5101 param.span,
5102 format!("this could be changed to `{}: ?Sized`...", param.name.ident()),
5103 );
5104 for sp in visitor.invalid_spans {
5105 multispan.push_span_label(
5106 sp,
5107 format!("...if indirection were used here: `Box<{}>`", param.name.ident()),
5108 );
5109 }
5110 err.span_help(
5111 multispan,
5112 format!(
5113 "you could relax the implicit `Sized` bound on `{T}` if it were \
5114 used through indirection like `&{T}` or `Box<{T}>`",
5115 T = param.name.ident(),
5116 ),
5117 );
5118 true
5119 }
5120 pub(crate) fn suggest_swapping_lhs_and_rhs<T>(
5121 &self,
5122 err: &mut Diag<'_>,
5123 predicate: T,
5124 param_env: ty::ParamEnv<'tcx>,
5125 cause_code: &ObligationCauseCode<'tcx>,
5126 ) where
5127 T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
5128 {
5129 let tcx = self.tcx;
5130 let predicate = predicate.upcast(tcx);
5131 match *cause_code {
5132 ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, rhs_span, .. }
5133 if let Some(typeck_results) = &self.typeck_results
5134 && let hir::Node::Expr(lhs) = tcx.hir_node(lhs_hir_id)
5135 && let hir::Node::Expr(rhs) = tcx.hir_node(rhs_hir_id)
5136 && let Some(lhs_ty) = typeck_results.expr_ty_opt(lhs)
5137 && let Some(rhs_ty) = typeck_results.expr_ty_opt(rhs) =>
5138 {
5139 if let Some(pred) = predicate.as_trait_clause()
5140 && tcx.is_lang_item(pred.def_id(), LangItem::PartialEq)
5141 && self
5142 .infcx
5143 .type_implements_trait(pred.def_id(), [rhs_ty, lhs_ty], param_env)
5144 .must_apply_modulo_regions()
5145 {
5146 let lhs_span = tcx.hir_span(lhs_hir_id);
5147 let sm = tcx.sess.source_map();
5148 if let Ok(rhs_snippet) = sm.span_to_snippet(rhs_span)
5149 && let Ok(lhs_snippet) = sm.span_to_snippet(lhs_span)
5150 {
5151 err.note(format!("`{rhs_ty}` implements `PartialEq<{lhs_ty}>`"));
5152 err.multipart_suggestion(
5153 "consider swapping the equality",
5154 vec![(lhs_span, rhs_snippet), (rhs_span, lhs_snippet)],
5155 Applicability::MaybeIncorrect,
5156 );
5157 }
5158 }
5159 }
5160 _ => {}
5161 }
5162 }
5163}
5164
5165fn hint_missing_borrow<'tcx>(
5167 infcx: &InferCtxt<'tcx>,
5168 param_env: ty::ParamEnv<'tcx>,
5169 span: Span,
5170 found: Ty<'tcx>,
5171 expected: Ty<'tcx>,
5172 found_node: Node<'_>,
5173 err: &mut Diag<'_>,
5174) {
5175 if matches!(found_node, Node::TraitItem(..)) {
5176 return;
5177 }
5178
5179 let found_args = match found.kind() {
5180 ty::FnPtr(sig_tys, _) => infcx.enter_forall(*sig_tys, |sig_tys| sig_tys.inputs().iter()),
5181 kind => {
5182 span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
5183 }
5184 };
5185 let expected_args = match expected.kind() {
5186 ty::FnPtr(sig_tys, _) => infcx.enter_forall(*sig_tys, |sig_tys| sig_tys.inputs().iter()),
5187 kind => {
5188 span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind)
5189 }
5190 };
5191
5192 let Some(fn_decl) = found_node.fn_decl() else {
5194 return;
5195 };
5196
5197 let args = fn_decl.inputs.iter();
5198
5199 let mut to_borrow = Vec::new();
5200 let mut remove_borrow = Vec::new();
5201
5202 for ((found_arg, expected_arg), arg) in found_args.zip(expected_args).zip(args) {
5203 let (found_ty, found_refs) = get_deref_type_and_refs(*found_arg);
5204 let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg);
5205
5206 if infcx.can_eq(param_env, found_ty, expected_ty) {
5207 if found_refs.len() < expected_refs.len()
5209 && found_refs[..] == expected_refs[expected_refs.len() - found_refs.len()..]
5210 {
5211 to_borrow.push((
5212 arg.span.shrink_to_lo(),
5213 expected_refs[..expected_refs.len() - found_refs.len()]
5214 .iter()
5215 .map(|mutbl| format!("&{}", mutbl.prefix_str()))
5216 .collect::<Vec<_>>()
5217 .join(""),
5218 ));
5219 } else if found_refs.len() > expected_refs.len() {
5220 let mut span = arg.span.shrink_to_lo();
5221 let mut left = found_refs.len() - expected_refs.len();
5222 let mut ty = arg;
5223 while let hir::TyKind::Ref(_, mut_ty) = &ty.kind
5224 && left > 0
5225 {
5226 span = span.with_hi(mut_ty.ty.span.lo());
5227 ty = mut_ty.ty;
5228 left -= 1;
5229 }
5230 let sugg = if left == 0 {
5231 (span, String::new())
5232 } else {
5233 (arg.span, expected_arg.to_string())
5234 };
5235 remove_borrow.push(sugg);
5236 }
5237 }
5238 }
5239
5240 if !to_borrow.is_empty() {
5241 err.subdiagnostic(errors::AdjustSignatureBorrow::Borrow { to_borrow });
5242 }
5243
5244 if !remove_borrow.is_empty() {
5245 err.subdiagnostic(errors::AdjustSignatureBorrow::RemoveBorrow { remove_borrow });
5246 }
5247}
5248
5249#[derive(Debug)]
5252pub struct SelfVisitor<'v> {
5253 pub paths: Vec<&'v hir::Ty<'v>> = Vec::new(),
5254 pub name: Option<Symbol>,
5255}
5256
5257impl<'v> Visitor<'v> for SelfVisitor<'v> {
5258 fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
5259 if let hir::TyKind::Path(path) = ty.kind
5260 && let hir::QPath::TypeRelative(inner_ty, segment) = path
5261 && (Some(segment.ident.name) == self.name || self.name.is_none())
5262 && let hir::TyKind::Path(inner_path) = inner_ty.kind
5263 && let hir::QPath::Resolved(None, inner_path) = inner_path
5264 && let Res::SelfTyAlias { .. } = inner_path.res
5265 {
5266 self.paths.push(ty.as_unambig_ty());
5267 }
5268 hir::intravisit::walk_ty(self, ty);
5269 }
5270}
5271
5272#[derive(Default)]
5275pub struct ReturnsVisitor<'v> {
5276 pub returns: Vec<&'v hir::Expr<'v>>,
5277 in_block_tail: bool,
5278}
5279
5280impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
5281 fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
5282 match ex.kind {
5287 hir::ExprKind::Ret(Some(ex)) => {
5288 self.returns.push(ex);
5289 }
5290 hir::ExprKind::Block(block, _) if self.in_block_tail => {
5291 self.in_block_tail = false;
5292 for stmt in block.stmts {
5293 hir::intravisit::walk_stmt(self, stmt);
5294 }
5295 self.in_block_tail = true;
5296 if let Some(expr) = block.expr {
5297 self.visit_expr(expr);
5298 }
5299 }
5300 hir::ExprKind::If(_, then, else_opt) if self.in_block_tail => {
5301 self.visit_expr(then);
5302 if let Some(el) = else_opt {
5303 self.visit_expr(el);
5304 }
5305 }
5306 hir::ExprKind::Match(_, arms, _) if self.in_block_tail => {
5307 for arm in arms {
5308 self.visit_expr(arm.body);
5309 }
5310 }
5311 _ if !self.in_block_tail => hir::intravisit::walk_expr(self, ex),
5313 _ => self.returns.push(ex),
5314 }
5315 }
5316
5317 fn visit_body(&mut self, body: &hir::Body<'v>) {
5318 assert!(!self.in_block_tail);
5319 self.in_block_tail = true;
5320 hir::intravisit::walk_body(self, body);
5321 }
5322}
5323
5324#[derive(Default)]
5326struct AwaitsVisitor {
5327 awaits: Vec<HirId>,
5328}
5329
5330impl<'v> Visitor<'v> for AwaitsVisitor {
5331 fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
5332 if let hir::ExprKind::Yield(_, hir::YieldSource::Await { expr: Some(id) }) = ex.kind {
5333 self.awaits.push(id)
5334 }
5335 hir::intravisit::walk_expr(self, ex)
5336 }
5337}
5338
5339pub trait NextTypeParamName {
5343 fn next_type_param_name(&self, name: Option<&str>) -> String;
5344}
5345
5346impl NextTypeParamName for &[hir::GenericParam<'_>] {
5347 fn next_type_param_name(&self, name: Option<&str>) -> String {
5348 let name = name.and_then(|n| n.chars().next()).map(|c| c.to_uppercase().to_string());
5350 let name = name.as_deref();
5351
5352 let possible_names = [name.unwrap_or("T"), "T", "U", "V", "X", "Y", "Z", "A", "B", "C"];
5354
5355 let used_names: Vec<Symbol> = self
5357 .iter()
5358 .filter_map(|param| match param.name {
5359 hir::ParamName::Plain(ident) => Some(ident.name),
5360 _ => None,
5361 })
5362 .collect();
5363
5364 possible_names
5366 .iter()
5367 .find(|n| !used_names.contains(&Symbol::intern(n)))
5368 .unwrap_or(&"ParamName")
5369 .to_string()
5370 }
5371}
5372
5373struct ReplaceImplTraitVisitor<'a> {
5375 ty_spans: &'a mut Vec<Span>,
5376 param_did: DefId,
5377}
5378
5379impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> {
5380 fn visit_ty(&mut self, t: &'hir hir::Ty<'hir, AmbigArg>) {
5381 if let hir::TyKind::Path(hir::QPath::Resolved(
5382 None,
5383 hir::Path { res: Res::Def(_, segment_did), .. },
5384 )) = t.kind
5385 {
5386 if self.param_did == *segment_did {
5387 self.ty_spans.push(t.span);
5392 return;
5393 }
5394 }
5395
5396 hir::intravisit::walk_ty(self, t);
5397 }
5398}
5399
5400pub(super) fn get_explanation_based_on_obligation<'tcx>(
5401 tcx: TyCtxt<'tcx>,
5402 obligation: &PredicateObligation<'tcx>,
5403 trait_predicate: ty::PolyTraitPredicate<'tcx>,
5404 pre_message: String,
5405 long_ty_path: &mut Option<PathBuf>,
5406) -> String {
5407 if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
5408 "consider using `()`, or a `Result`".to_owned()
5409 } else {
5410 let ty_desc = match trait_predicate.self_ty().skip_binder().kind() {
5411 ty::FnDef(_, _) => Some("fn item"),
5412 ty::Closure(_, _) => Some("closure"),
5413 _ => None,
5414 };
5415
5416 let desc = match ty_desc {
5417 Some(desc) => format!(" {desc}"),
5418 None => String::new(),
5419 };
5420 if let ty::PredicatePolarity::Positive = trait_predicate.polarity() {
5421 format!(
5422 "{pre_message}the trait `{}` is not implemented for{desc} `{}`",
5423 trait_predicate.print_modifiers_and_trait_path(),
5424 tcx.short_string(trait_predicate.self_ty().skip_binder(), long_ty_path),
5425 )
5426 } else {
5427 format!("{pre_message}the trait bound `{trait_predicate}` is not satisfied")
5431 }
5432 }
5433}
5434
5435struct ReplaceImplTraitFolder<'tcx> {
5437 tcx: TyCtxt<'tcx>,
5438 param: &'tcx ty::GenericParamDef,
5439 replace_ty: Ty<'tcx>,
5440}
5441
5442impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceImplTraitFolder<'tcx> {
5443 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
5444 if let ty::Param(ty::ParamTy { index, .. }) = t.kind() {
5445 if self.param.index == *index {
5446 return self.replace_ty;
5447 }
5448 }
5449 t.super_fold_with(self)
5450 }
5451
5452 fn cx(&self) -> TyCtxt<'tcx> {
5453 self.tcx
5454 }
5455}
5456
5457pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>(
5458 tcx: TyCtxt<'tcx>,
5459 sig: hir::FnSig<'tcx>,
5460 body: hir::TraitFn<'tcx>,
5461 opaque_def_id: LocalDefId,
5462 add_bounds: &str,
5463) -> Option<Vec<(Span, String)>> {
5464 let hir::IsAsync::Async(async_span) = sig.header.asyncness else {
5465 return None;
5466 };
5467 let async_span = tcx.sess.source_map().span_extend_while_whitespace(async_span);
5468
5469 let future = tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty();
5470 let [hir::GenericBound::Trait(trait_ref)] = future.bounds else {
5471 return None;
5473 };
5474 let Some(hir::PathSegment { args: Some(args), .. }) = trait_ref.trait_ref.path.segments.last()
5475 else {
5476 return None;
5478 };
5479 let Some(future_output_ty) = args.constraints.first().and_then(|constraint| constraint.ty())
5480 else {
5481 return None;
5483 };
5484
5485 let mut sugg = if future_output_ty.span.is_empty() {
5486 vec![
5487 (async_span, String::new()),
5488 (
5489 future_output_ty.span,
5490 format!(" -> impl std::future::Future<Output = ()>{add_bounds}"),
5491 ),
5492 ]
5493 } else {
5494 vec![
5495 (future_output_ty.span.shrink_to_lo(), "impl std::future::Future<Output = ".to_owned()),
5496 (future_output_ty.span.shrink_to_hi(), format!(">{add_bounds}")),
5497 (async_span, String::new()),
5498 ]
5499 };
5500
5501 if let hir::TraitFn::Provided(body) = body {
5503 let body = tcx.hir_body(body);
5504 let body_span = body.value.span;
5505 let body_span_without_braces =
5506 body_span.with_lo(body_span.lo() + BytePos(1)).with_hi(body_span.hi() - BytePos(1));
5507 if body_span_without_braces.is_empty() {
5508 sugg.push((body_span_without_braces, " async {} ".to_owned()));
5509 } else {
5510 sugg.extend([
5511 (body_span_without_braces.shrink_to_lo(), "async {".to_owned()),
5512 (body_span_without_braces.shrink_to_hi(), "} ".to_owned()),
5513 ]);
5514 }
5515 }
5516
5517 Some(sugg)
5518}
5519
5520fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
5523 tcx: TyCtxt<'_>,
5524 err: &mut Diag<'_, G>,
5525 self_ty_str: &str,
5526 trait_name: &str,
5527 predicate: ty::Predicate<'_>,
5528 generics: &hir::Generics<'_>,
5529 data: &ImplDerivedCause<'_>,
5530) {
5531 let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() else {
5532 return;
5533 };
5534 let ty::ClauseKind::Projection(proj) = clause else {
5535 return;
5536 };
5537 let name = tcx.item_name(proj.projection_term.def_id);
5538 let mut predicates = generics.predicates.iter().peekable();
5539 let mut prev: Option<(&hir::WhereBoundPredicate<'_>, Span)> = None;
5540 while let Some(pred) = predicates.next() {
5541 let curr_span = pred.span;
5542 let hir::WherePredicateKind::BoundPredicate(pred) = pred.kind else {
5543 continue;
5544 };
5545 let mut bounds = pred.bounds.iter();
5546 while let Some(bound) = bounds.next() {
5547 let Some(trait_ref) = bound.trait_ref() else {
5548 continue;
5549 };
5550 if bound.span() != data.span {
5551 continue;
5552 }
5553 if let hir::TyKind::Path(path) = pred.bounded_ty.kind
5554 && let hir::QPath::TypeRelative(ty, segment) = path
5555 && segment.ident.name == name
5556 && let hir::TyKind::Path(inner_path) = ty.kind
5557 && let hir::QPath::Resolved(None, inner_path) = inner_path
5558 && let Res::SelfTyAlias { .. } = inner_path.res
5559 {
5560 let span = if pred.origin == hir::PredicateOrigin::WhereClause
5563 && generics
5564 .predicates
5565 .iter()
5566 .filter(|p| {
5567 matches!(
5568 p.kind,
5569 hir::WherePredicateKind::BoundPredicate(p)
5570 if hir::PredicateOrigin::WhereClause == p.origin
5571 )
5572 })
5573 .count()
5574 == 1
5575 {
5576 generics.where_clause_span
5579 } else if let Some(next_pred) = predicates.peek()
5580 && let hir::WherePredicateKind::BoundPredicate(next) = next_pred.kind
5581 && pred.origin == next.origin
5582 {
5583 curr_span.until(next_pred.span)
5585 } else if let Some((prev, prev_span)) = prev
5586 && pred.origin == prev.origin
5587 {
5588 prev_span.shrink_to_hi().to(curr_span)
5590 } else if pred.origin == hir::PredicateOrigin::WhereClause {
5591 curr_span.with_hi(generics.where_clause_span.hi())
5592 } else {
5593 curr_span
5594 };
5595
5596 err.span_suggestion_verbose(
5597 span,
5598 "associated type for the current `impl` cannot be restricted in `where` \
5599 clauses, remove this bound",
5600 "",
5601 Applicability::MaybeIncorrect,
5602 );
5603 }
5604 if let Some(new) =
5605 tcx.associated_items(data.impl_or_alias_def_id).find_by_ident_and_kind(
5606 tcx,
5607 Ident::with_dummy_span(name),
5608 ty::AssocTag::Type,
5609 data.impl_or_alias_def_id,
5610 )
5611 {
5612 let span = tcx.def_span(new.def_id);
5615 err.span_label(
5616 span,
5617 format!(
5618 "associated type `<{self_ty_str} as {trait_name}>::{name}` is specified \
5619 here",
5620 ),
5621 );
5622 let mut visitor = SelfVisitor { name: Some(name), .. };
5625 visitor.visit_trait_ref(trait_ref);
5626 for path in visitor.paths {
5627 err.span_suggestion_verbose(
5628 path.span,
5629 "replace the associated type with the type specified in this `impl`",
5630 tcx.type_of(new.def_id).skip_binder(),
5631 Applicability::MachineApplicable,
5632 );
5633 }
5634 } else {
5635 let mut visitor = SelfVisitor { name: None, .. };
5636 visitor.visit_trait_ref(trait_ref);
5637 let span: MultiSpan =
5638 visitor.paths.iter().map(|p| p.span).collect::<Vec<Span>>().into();
5639 err.span_note(
5640 span,
5641 "associated types for the current `impl` cannot be restricted in `where` \
5642 clauses",
5643 );
5644 }
5645 }
5646 prev = Some((pred, curr_span));
5647 }
5648}
5649
5650fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
5651 let mut refs = vec![];
5652
5653 while let ty::Ref(_, new_ty, mutbl) = ty.kind() {
5654 ty = *new_ty;
5655 refs.push(*mutbl);
5656 }
5657
5658 (ty, refs)
5659}
5660
5661struct FindTypeParam {
5664 param: rustc_span::Symbol,
5665 invalid_spans: Vec<Span> = Vec::new(),
5666 nested: bool = false,
5667}
5668
5669impl<'v> Visitor<'v> for FindTypeParam {
5670 fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) {
5671 }
5673
5674 fn visit_ty(&mut self, ty: &hir::Ty<'_, AmbigArg>) {
5675 match ty.kind {
5682 hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {}
5683 hir::TyKind::Path(hir::QPath::Resolved(None, path))
5684 if let [segment] = path.segments
5685 && segment.ident.name == self.param =>
5686 {
5687 if !self.nested {
5688 debug!(?ty, "FindTypeParam::visit_ty");
5689 self.invalid_spans.push(ty.span);
5690 }
5691 }
5692 hir::TyKind::Path(_) => {
5693 let prev = self.nested;
5694 self.nested = true;
5695 hir::intravisit::walk_ty(self, ty);
5696 self.nested = prev;
5697 }
5698 _ => {
5699 hir::intravisit::walk_ty(self, ty);
5700 }
5701 }
5702 }
5703}
5704
5705struct ParamFinder {
5708 params: Vec<Symbol> = Vec::new(),
5709}
5710
5711impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParamFinder {
5712 fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
5713 match t.kind() {
5714 ty::Param(p) => self.params.push(p.name),
5715 _ => {}
5716 }
5717 t.super_visit_with(self)
5718 }
5719}
5720
5721impl ParamFinder {
5722 fn can_suggest_bound(&self, generics: &hir::Generics<'_>) -> bool {
5725 if self.params.is_empty() {
5726 return true;
5729 }
5730 generics.params.iter().any(|p| match p.name {
5731 hir::ParamName::Plain(p_name) => {
5732 self.params.iter().any(|p| *p == p_name.name || *p == kw::SelfUpper)
5734 }
5735 _ => true,
5736 })
5737 }
5738}