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, _) => 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, _) = 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(_, _) = 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 if tcx.is_diagnostic_item(sym::PinDerefMutHelper, parent_def_id) {
3480 let parent_predicate =
3481 self.resolve_vars_if_possible(data.derived.parent_trait_pred);
3482
3483 ensure_sufficient_stack(|| {
3485 self.note_obligation_cause_code(
3486 body_id,
3487 err,
3488 parent_predicate,
3489 param_env,
3490 &data.derived.parent_code,
3491 obligated_types,
3492 seen_requirements,
3493 )
3494 });
3495 return;
3496 }
3497 let self_ty_str =
3498 tcx.short_string(parent_trait_pred.skip_binder().self_ty(), err.long_ty_path());
3499 let trait_name = tcx.short_string(
3500 parent_trait_pred.print_modifiers_and_trait_path(),
3501 err.long_ty_path(),
3502 );
3503 let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`");
3504 let mut is_auto_trait = false;
3505 match tcx.hir_get_if_local(data.impl_or_alias_def_id) {
3506 Some(Node::Item(hir::Item {
3507 kind: hir::ItemKind::Trait(_, is_auto, _, ident, ..),
3508 ..
3509 })) => {
3510 is_auto_trait = matches!(is_auto, hir::IsAuto::Yes);
3513 err.span_note(ident.span, msg);
3514 }
3515 Some(Node::Item(hir::Item {
3516 kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, generics, .. }),
3517 ..
3518 })) => {
3519 let mut spans = Vec::with_capacity(2);
3520 if let Some(of_trait) = of_trait {
3521 spans.push(of_trait.trait_ref.path.span);
3522 }
3523 spans.push(self_ty.span);
3524 let mut spans: MultiSpan = spans.into();
3525 if matches!(
3526 self_ty.span.ctxt().outer_expn_data().kind,
3527 ExpnKind::Macro(MacroKind::Derive, _)
3528 ) || matches!(
3529 of_trait.map(|t| t.trait_ref.path.span.ctxt().outer_expn_data().kind),
3530 Some(ExpnKind::Macro(MacroKind::Derive, _))
3531 ) {
3532 spans.push_span_label(
3533 data.span,
3534 "unsatisfied trait bound introduced in this `derive` macro",
3535 );
3536 } else if !data.span.is_dummy() && !data.span.overlaps(self_ty.span) {
3537 spans.push_span_label(
3538 data.span,
3539 "unsatisfied trait bound introduced here",
3540 );
3541 }
3542 err.span_note(spans, msg);
3543 point_at_assoc_type_restriction(
3544 tcx,
3545 err,
3546 &self_ty_str,
3547 &trait_name,
3548 predicate,
3549 &generics,
3550 &data,
3551 );
3552 }
3553 _ => {
3554 err.note(msg);
3555 }
3556 };
3557
3558 let mut parent_predicate = parent_trait_pred;
3559 let mut data = &data.derived;
3560 let mut count = 0;
3561 seen_requirements.insert(parent_def_id);
3562 if is_auto_trait {
3563 while let ObligationCauseCode::BuiltinDerived(derived) = &*data.parent_code {
3566 let child_trait_ref =
3567 self.resolve_vars_if_possible(derived.parent_trait_pred);
3568 let child_def_id = child_trait_ref.def_id();
3569 if seen_requirements.insert(child_def_id) {
3570 break;
3571 }
3572 data = derived;
3573 parent_predicate = child_trait_ref.upcast(tcx);
3574 parent_trait_pred = child_trait_ref;
3575 }
3576 }
3577 while let ObligationCauseCode::ImplDerived(child) = &*data.parent_code {
3578 let child_trait_pred =
3580 self.resolve_vars_if_possible(child.derived.parent_trait_pred);
3581 let child_def_id = child_trait_pred.def_id();
3582 if seen_requirements.insert(child_def_id) {
3583 break;
3584 }
3585 count += 1;
3586 data = &child.derived;
3587 parent_predicate = child_trait_pred.upcast(tcx);
3588 parent_trait_pred = child_trait_pred;
3589 }
3590 if count > 0 {
3591 err.note(format!(
3592 "{} redundant requirement{} hidden",
3593 count,
3594 pluralize!(count)
3595 ));
3596 let self_ty = tcx.short_string(
3597 parent_trait_pred.skip_binder().self_ty(),
3598 err.long_ty_path(),
3599 );
3600 let trait_path = tcx.short_string(
3601 parent_trait_pred.print_modifiers_and_trait_path(),
3602 err.long_ty_path(),
3603 );
3604 err.note(format!("required for `{self_ty}` to implement `{trait_path}`"));
3605 }
3606 ensure_sufficient_stack(|| {
3608 self.note_obligation_cause_code(
3609 body_id,
3610 err,
3611 parent_predicate,
3612 param_env,
3613 &data.parent_code,
3614 obligated_types,
3615 seen_requirements,
3616 )
3617 });
3618 }
3619 ObligationCauseCode::ImplDerivedHost(ref data) => {
3620 let self_ty = tcx.short_string(
3621 self.resolve_vars_if_possible(data.derived.parent_host_pred.self_ty()),
3622 err.long_ty_path(),
3623 );
3624 let trait_path = tcx.short_string(
3625 data.derived
3626 .parent_host_pred
3627 .map_bound(|pred| pred.trait_ref)
3628 .print_only_trait_path(),
3629 err.long_ty_path(),
3630 );
3631 let msg = format!(
3632 "required for `{self_ty}` to implement `{} {trait_path}`",
3633 data.derived.parent_host_pred.skip_binder().constness,
3634 );
3635 match tcx.hir_get_if_local(data.impl_def_id) {
3636 Some(Node::Item(hir::Item {
3637 kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
3638 ..
3639 })) => {
3640 let mut spans = vec![self_ty.span];
3641 spans.extend(of_trait.map(|t| t.trait_ref.path.span));
3642 let mut spans: MultiSpan = spans.into();
3643 spans.push_span_label(data.span, "unsatisfied trait bound introduced here");
3644 err.span_note(spans, msg);
3645 }
3646 _ => {
3647 err.note(msg);
3648 }
3649 }
3650 ensure_sufficient_stack(|| {
3651 self.note_obligation_cause_code(
3652 body_id,
3653 err,
3654 data.derived.parent_host_pred,
3655 param_env,
3656 &data.derived.parent_code,
3657 obligated_types,
3658 seen_requirements,
3659 )
3660 });
3661 }
3662 ObligationCauseCode::BuiltinDerivedHost(ref data) => {
3663 ensure_sufficient_stack(|| {
3664 self.note_obligation_cause_code(
3665 body_id,
3666 err,
3667 data.parent_host_pred,
3668 param_env,
3669 &data.parent_code,
3670 obligated_types,
3671 seen_requirements,
3672 )
3673 });
3674 }
3675 ObligationCauseCode::WellFormedDerived(ref data) => {
3676 let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
3677 let parent_predicate = parent_trait_ref;
3678 ensure_sufficient_stack(|| {
3680 self.note_obligation_cause_code(
3681 body_id,
3682 err,
3683 parent_predicate,
3684 param_env,
3685 &data.parent_code,
3686 obligated_types,
3687 seen_requirements,
3688 )
3689 });
3690 }
3691 ObligationCauseCode::TypeAlias(ref nested, span, def_id) => {
3692 ensure_sufficient_stack(|| {
3694 self.note_obligation_cause_code(
3695 body_id,
3696 err,
3697 predicate,
3698 param_env,
3699 nested,
3700 obligated_types,
3701 seen_requirements,
3702 )
3703 });
3704 let mut multispan = MultiSpan::from(span);
3705 multispan.push_span_label(span, "required by this bound");
3706 err.span_note(
3707 multispan,
3708 format!("required by a bound on the type alias `{}`", tcx.item_name(def_id)),
3709 );
3710 }
3711 ObligationCauseCode::FunctionArg {
3712 arg_hir_id, call_hir_id, ref parent_code, ..
3713 } => {
3714 self.note_function_argument_obligation(
3715 body_id,
3716 err,
3717 arg_hir_id,
3718 parent_code,
3719 param_env,
3720 predicate,
3721 call_hir_id,
3722 );
3723 ensure_sufficient_stack(|| {
3724 self.note_obligation_cause_code(
3725 body_id,
3726 err,
3727 predicate,
3728 param_env,
3729 parent_code,
3730 obligated_types,
3731 seen_requirements,
3732 )
3733 });
3734 }
3735 ObligationCauseCode::CompareImplItem { trait_item_def_id, .. }
3738 if tcx.is_impl_trait_in_trait(trait_item_def_id) => {}
3739 ObligationCauseCode::CompareImplItem { trait_item_def_id, kind, .. } => {
3740 let item_name = tcx.item_name(trait_item_def_id);
3741 let msg = format!(
3742 "the requirement `{predicate}` appears on the `impl`'s {kind} \
3743 `{item_name}` but not on the corresponding trait's {kind}",
3744 );
3745 let sp = tcx
3746 .opt_item_ident(trait_item_def_id)
3747 .map(|i| i.span)
3748 .unwrap_or_else(|| tcx.def_span(trait_item_def_id));
3749 let mut assoc_span: MultiSpan = sp.into();
3750 assoc_span.push_span_label(
3751 sp,
3752 format!("this trait's {kind} doesn't have the requirement `{predicate}`"),
3753 );
3754 if let Some(ident) = tcx
3755 .opt_associated_item(trait_item_def_id)
3756 .and_then(|i| tcx.opt_item_ident(i.container_id(tcx)))
3757 {
3758 assoc_span.push_span_label(ident.span, "in this trait");
3759 }
3760 err.span_note(assoc_span, msg);
3761 }
3762 ObligationCauseCode::TrivialBound => {
3763 err.help("see issue #48214");
3764 tcx.disabled_nightly_features(err, [(String::new(), sym::trivial_bounds)]);
3765 }
3766 ObligationCauseCode::OpaqueReturnType(expr_info) => {
3767 let (expr_ty, expr) = if let Some((expr_ty, hir_id)) = expr_info {
3768 let expr_ty = tcx.short_string(expr_ty, err.long_ty_path());
3769 let expr = tcx.hir_expect_expr(hir_id);
3770 (expr_ty, expr)
3771 } else if let Some(body_id) = tcx.hir_node_by_def_id(body_id).body_id()
3772 && let body = tcx.hir_body(body_id)
3773 && let hir::ExprKind::Block(block, _) = body.value.kind
3774 && let Some(expr) = block.expr
3775 && let Some(expr_ty) = self
3776 .typeck_results
3777 .as_ref()
3778 .and_then(|typeck| typeck.node_type_opt(expr.hir_id))
3779 && let Some(pred) = predicate.as_clause()
3780 && let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder()
3781 && self.can_eq(param_env, pred.self_ty(), expr_ty)
3782 {
3783 let expr_ty = tcx.short_string(expr_ty, err.long_ty_path());
3784 (expr_ty, expr)
3785 } else {
3786 return;
3787 };
3788 err.span_label(
3789 expr.span,
3790 with_forced_trimmed_paths!(format!(
3791 "return type was inferred to be `{expr_ty}` here",
3792 )),
3793 );
3794 suggest_remove_deref(err, &expr);
3795 }
3796 ObligationCauseCode::UnsizedNonPlaceExpr(span) => {
3797 err.span_note(
3798 span,
3799 "unsized values must be place expressions and cannot be put in temporaries",
3800 );
3801 }
3802 }
3803 }
3804
3805 #[instrument(
3806 level = "debug", skip(self, err), fields(trait_pred.self_ty = ?trait_pred.self_ty())
3807 )]
3808 pub(super) fn suggest_await_before_try(
3809 &self,
3810 err: &mut Diag<'_>,
3811 obligation: &PredicateObligation<'tcx>,
3812 trait_pred: ty::PolyTraitPredicate<'tcx>,
3813 span: Span,
3814 ) {
3815 let future_trait = self.tcx.require_lang_item(LangItem::Future, span);
3816
3817 let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
3818 let impls_future = self.type_implements_trait(
3819 future_trait,
3820 [self.tcx.instantiate_bound_regions_with_erased(self_ty)],
3821 obligation.param_env,
3822 );
3823 if !impls_future.must_apply_modulo_regions() {
3824 return;
3825 }
3826
3827 let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
3828 let projection_ty = trait_pred.map_bound(|trait_pred| {
3830 Ty::new_projection(
3831 self.tcx,
3832 item_def_id,
3833 [trait_pred.self_ty()],
3835 )
3836 });
3837 let InferOk { value: projection_ty, .. } =
3838 self.at(&obligation.cause, obligation.param_env).normalize(projection_ty);
3839
3840 debug!(
3841 normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty)
3842 );
3843 let try_obligation = self.mk_trait_obligation_with_new_self_ty(
3844 obligation.param_env,
3845 trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())),
3846 );
3847 debug!(try_trait_obligation = ?try_obligation);
3848 if self.predicate_may_hold(&try_obligation)
3849 && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
3850 && snippet.ends_with('?')
3851 {
3852 match self.tcx.coroutine_kind(obligation.cause.body_id) {
3853 Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
3854 err.span_suggestion_verbose(
3855 span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(),
3856 "consider `await`ing on the `Future`",
3857 ".await",
3858 Applicability::MaybeIncorrect,
3859 );
3860 }
3861 _ => {
3862 let mut span: MultiSpan = span.with_lo(span.hi() - BytePos(1)).into();
3863 span.push_span_label(
3864 self.tcx.def_span(obligation.cause.body_id),
3865 "this is not `async`",
3866 );
3867 err.span_note(
3868 span,
3869 "this implements `Future` and its output type supports \
3870 `?`, but the future cannot be awaited in a synchronous function",
3871 );
3872 }
3873 }
3874 }
3875 }
3876
3877 pub(super) fn suggest_floating_point_literal(
3878 &self,
3879 obligation: &PredicateObligation<'tcx>,
3880 err: &mut Diag<'_>,
3881 trait_pred: ty::PolyTraitPredicate<'tcx>,
3882 ) {
3883 let rhs_span = match obligation.cause.code() {
3884 ObligationCauseCode::BinOp { rhs_span, rhs_is_lit, .. } if *rhs_is_lit => rhs_span,
3885 _ => return,
3886 };
3887 if let ty::Float(_) = trait_pred.skip_binder().self_ty().kind()
3888 && let ty::Infer(InferTy::IntVar(_)) =
3889 trait_pred.skip_binder().trait_ref.args.type_at(1).kind()
3890 {
3891 err.span_suggestion_verbose(
3892 rhs_span.shrink_to_hi(),
3893 "consider using a floating-point literal by writing it with `.0`",
3894 ".0",
3895 Applicability::MaybeIncorrect,
3896 );
3897 }
3898 }
3899
3900 pub fn can_suggest_derive(
3901 &self,
3902 obligation: &PredicateObligation<'tcx>,
3903 trait_pred: ty::PolyTraitPredicate<'tcx>,
3904 ) -> bool {
3905 if trait_pred.polarity() == ty::PredicatePolarity::Negative {
3906 return false;
3907 }
3908 let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) else {
3909 return false;
3910 };
3911 let (adt, args) = match trait_pred.skip_binder().self_ty().kind() {
3912 ty::Adt(adt, args) if adt.did().is_local() => (adt, args),
3913 _ => return false,
3914 };
3915 let is_derivable_trait = match diagnostic_name {
3916 sym::Default => !adt.is_enum(),
3917 sym::PartialEq | sym::PartialOrd => {
3918 let rhs_ty = trait_pred.skip_binder().trait_ref.args.type_at(1);
3919 trait_pred.skip_binder().self_ty() == rhs_ty
3920 }
3921 sym::Eq | sym::Ord | sym::Clone | sym::Copy | sym::Hash | sym::Debug => true,
3922 _ => false,
3923 };
3924 is_derivable_trait &&
3925 adt.all_fields().all(|field| {
3927 let field_ty = ty::GenericArg::from(field.ty(self.tcx, args));
3928 let trait_args = match diagnostic_name {
3929 sym::PartialEq | sym::PartialOrd => {
3930 Some(field_ty)
3931 }
3932 _ => None,
3933 };
3934 let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate {
3935 trait_ref: ty::TraitRef::new(self.tcx,
3936 trait_pred.def_id(),
3937 [field_ty].into_iter().chain(trait_args),
3938 ),
3939 ..*tr
3940 });
3941 let field_obl = Obligation::new(
3942 self.tcx,
3943 obligation.cause.clone(),
3944 obligation.param_env,
3945 trait_pred,
3946 );
3947 self.predicate_must_hold_modulo_regions(&field_obl)
3948 })
3949 }
3950
3951 pub fn suggest_derive(
3952 &self,
3953 obligation: &PredicateObligation<'tcx>,
3954 err: &mut Diag<'_>,
3955 trait_pred: ty::PolyTraitPredicate<'tcx>,
3956 ) {
3957 let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) else {
3958 return;
3959 };
3960 let adt = match trait_pred.skip_binder().self_ty().kind() {
3961 ty::Adt(adt, _) if adt.did().is_local() => adt,
3962 _ => return,
3963 };
3964 if self.can_suggest_derive(obligation, trait_pred) {
3965 err.span_suggestion_verbose(
3966 self.tcx.def_span(adt.did()).shrink_to_lo(),
3967 format!(
3968 "consider annotating `{}` with `#[derive({})]`",
3969 trait_pred.skip_binder().self_ty(),
3970 diagnostic_name,
3971 ),
3972 format!("#[derive({diagnostic_name})]\n"),
3974 Applicability::MaybeIncorrect,
3975 );
3976 }
3977 }
3978
3979 pub(super) fn suggest_dereferencing_index(
3980 &self,
3981 obligation: &PredicateObligation<'tcx>,
3982 err: &mut Diag<'_>,
3983 trait_pred: ty::PolyTraitPredicate<'tcx>,
3984 ) {
3985 if let ObligationCauseCode::ImplDerived(_) = obligation.cause.code()
3986 && self
3987 .tcx
3988 .is_diagnostic_item(sym::SliceIndex, trait_pred.skip_binder().trait_ref.def_id)
3989 && let ty::Slice(_) = trait_pred.skip_binder().trait_ref.args.type_at(1).kind()
3990 && let ty::Ref(_, inner_ty, _) = trait_pred.skip_binder().self_ty().kind()
3991 && let ty::Uint(ty::UintTy::Usize) = inner_ty.kind()
3992 {
3993 err.span_suggestion_verbose(
3994 obligation.cause.span.shrink_to_lo(),
3995 "dereference this index",
3996 '*',
3997 Applicability::MachineApplicable,
3998 );
3999 }
4000 }
4001
4002 fn note_function_argument_obligation<G: EmissionGuarantee>(
4003 &self,
4004 body_id: LocalDefId,
4005 err: &mut Diag<'_, G>,
4006 arg_hir_id: HirId,
4007 parent_code: &ObligationCauseCode<'tcx>,
4008 param_env: ty::ParamEnv<'tcx>,
4009 failed_pred: ty::Predicate<'tcx>,
4010 call_hir_id: HirId,
4011 ) {
4012 let tcx = self.tcx;
4013 if let Node::Expr(expr) = tcx.hir_node(arg_hir_id)
4014 && let Some(typeck_results) = &self.typeck_results
4015 {
4016 if let hir::Expr { kind: hir::ExprKind::MethodCall(_, rcvr, _, _), .. } = expr
4017 && let Some(ty) = typeck_results.node_type_opt(rcvr.hir_id)
4018 && let Some(failed_pred) = failed_pred.as_trait_clause()
4019 && let pred = failed_pred.map_bound(|pred| pred.with_replaced_self_ty(tcx, ty))
4020 && self.predicate_must_hold_modulo_regions(&Obligation::misc(
4021 tcx, expr.span, body_id, param_env, pred,
4022 ))
4023 && expr.span.hi() != rcvr.span.hi()
4024 {
4025 err.span_suggestion_verbose(
4026 expr.span.with_lo(rcvr.span.hi()),
4027 format!(
4028 "consider removing this method call, as the receiver has type `{ty}` and \
4029 `{pred}` trivially holds",
4030 ),
4031 "",
4032 Applicability::MaybeIncorrect,
4033 );
4034 }
4035 if let hir::Expr { kind: hir::ExprKind::Block(block, _), .. } = expr {
4036 let inner_expr = expr.peel_blocks();
4037 let ty = typeck_results
4038 .expr_ty_adjusted_opt(inner_expr)
4039 .unwrap_or(Ty::new_misc_error(tcx));
4040 let span = inner_expr.span;
4041 if Some(span) != err.span.primary_span()
4042 && !span.in_external_macro(tcx.sess.source_map())
4043 {
4044 err.span_label(
4045 span,
4046 if ty.references_error() {
4047 String::new()
4048 } else {
4049 let ty = with_forced_trimmed_paths!(self.ty_to_string(ty));
4050 format!("this tail expression is of type `{ty}`")
4051 },
4052 );
4053 if let ty::PredicateKind::Clause(clause) = failed_pred.kind().skip_binder()
4054 && let ty::ClauseKind::Trait(pred) = clause
4055 && tcx.fn_trait_kind_from_def_id(pred.def_id()).is_some()
4056 {
4057 if let [stmt, ..] = block.stmts
4058 && let hir::StmtKind::Semi(value) = stmt.kind
4059 && let hir::ExprKind::Closure(hir::Closure {
4060 body, fn_decl_span, ..
4061 }) = value.kind
4062 && let body = tcx.hir_body(*body)
4063 && !matches!(body.value.kind, hir::ExprKind::Block(..))
4064 {
4065 err.multipart_suggestion(
4068 "you might have meant to open the closure body instead of placing \
4069 a closure within a block",
4070 vec![
4071 (expr.span.with_hi(value.span.lo()), String::new()),
4072 (fn_decl_span.shrink_to_hi(), " {".to_string()),
4073 ],
4074 Applicability::MaybeIncorrect,
4075 );
4076 } else {
4077 err.span_suggestion_verbose(
4079 expr.span.shrink_to_lo(),
4080 "you might have meant to create the closure instead of a block",
4081 format!(
4082 "|{}| ",
4083 (0..pred.trait_ref.args.len() - 1)
4084 .map(|_| "_")
4085 .collect::<Vec<_>>()
4086 .join(", ")
4087 ),
4088 Applicability::MaybeIncorrect,
4089 );
4090 }
4091 }
4092 }
4093 }
4094
4095 let mut type_diffs = vec![];
4100 if let ObligationCauseCode::WhereClauseInExpr(def_id, _, _, idx) = parent_code
4101 && let Some(node_args) = typeck_results.node_args_opt(call_hir_id)
4102 && let where_clauses =
4103 self.tcx.predicates_of(def_id).instantiate(self.tcx, node_args)
4104 && let Some(where_pred) = where_clauses.predicates.get(*idx)
4105 {
4106 if let Some(where_pred) = where_pred.as_trait_clause()
4107 && let Some(failed_pred) = failed_pred.as_trait_clause()
4108 && where_pred.def_id() == failed_pred.def_id()
4109 {
4110 self.enter_forall(where_pred, |where_pred| {
4111 let failed_pred = self.instantiate_binder_with_fresh_vars(
4112 expr.span,
4113 BoundRegionConversionTime::FnCall,
4114 failed_pred,
4115 );
4116
4117 let zipped =
4118 iter::zip(where_pred.trait_ref.args, failed_pred.trait_ref.args);
4119 for (expected, actual) in zipped {
4120 self.probe(|_| {
4121 match self
4122 .at(&ObligationCause::misc(expr.span, body_id), param_env)
4123 .eq(DefineOpaqueTypes::Yes, expected, actual)
4126 {
4127 Ok(_) => (), Err(err) => type_diffs.push(err),
4129 }
4130 })
4131 }
4132 })
4133 } else if let Some(where_pred) = where_pred.as_projection_clause()
4134 && let Some(failed_pred) = failed_pred.as_projection_clause()
4135 && let Some(found) = failed_pred.skip_binder().term.as_type()
4136 {
4137 type_diffs = vec![TypeError::Sorts(ty::error::ExpectedFound {
4138 expected: where_pred
4139 .skip_binder()
4140 .projection_term
4141 .expect_ty(self.tcx)
4142 .to_ty(self.tcx),
4143 found,
4144 })];
4145 }
4146 }
4147 if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
4148 && let hir::Path { res: Res::Local(hir_id), .. } = path
4149 && let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id)
4150 && let hir::Node::LetStmt(local) = self.tcx.parent_hir_node(binding.hir_id)
4151 && let Some(binding_expr) = local.init
4152 {
4153 self.point_at_chain(binding_expr, typeck_results, type_diffs, param_env, err);
4157 } else {
4158 self.point_at_chain(expr, typeck_results, type_diffs, param_env, err);
4159 }
4160 }
4161 let call_node = tcx.hir_node(call_hir_id);
4162 if let Node::Expr(hir::Expr { kind: hir::ExprKind::MethodCall(path, rcvr, ..), .. }) =
4163 call_node
4164 {
4165 if Some(rcvr.span) == err.span.primary_span() {
4166 err.replace_span_with(path.ident.span, true);
4167 }
4168 }
4169
4170 if let Node::Expr(expr) = call_node {
4171 if let hir::ExprKind::Call(hir::Expr { span, .. }, _)
4172 | hir::ExprKind::MethodCall(
4173 hir::PathSegment { ident: Ident { span, .. }, .. },
4174 ..,
4175 ) = expr.kind
4176 {
4177 if Some(*span) != err.span.primary_span() {
4178 let msg = if span.is_desugaring(DesugaringKind::FormatLiteral { source: true })
4179 {
4180 "required by this formatting parameter"
4181 } else if span.is_desugaring(DesugaringKind::FormatLiteral { source: false }) {
4182 "required by a formatting parameter in this expression"
4183 } else {
4184 "required by a bound introduced by this call"
4185 };
4186 err.span_label(*span, msg);
4187 }
4188 }
4189
4190 if let hir::ExprKind::MethodCall(_, expr, ..) = expr.kind {
4191 self.suggest_option_method_if_applicable(failed_pred, param_env, err, expr);
4192 }
4193 }
4194 }
4195
4196 fn suggest_option_method_if_applicable<G: EmissionGuarantee>(
4197 &self,
4198 failed_pred: ty::Predicate<'tcx>,
4199 param_env: ty::ParamEnv<'tcx>,
4200 err: &mut Diag<'_, G>,
4201 expr: &hir::Expr<'_>,
4202 ) {
4203 let tcx = self.tcx;
4204 let infcx = self.infcx;
4205 let Some(typeck_results) = self.typeck_results.as_ref() else { return };
4206
4207 let Some(option_ty_adt) = typeck_results.expr_ty_adjusted(expr).ty_adt_def() else {
4209 return;
4210 };
4211 if !tcx.is_diagnostic_item(sym::Option, option_ty_adt.did()) {
4212 return;
4213 }
4214
4215 if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, .. }))
4218 = failed_pred.kind().skip_binder()
4219 && tcx.is_fn_trait(trait_ref.def_id)
4220 && let [self_ty, found_ty] = trait_ref.args.as_slice()
4221 && let Some(fn_ty) = self_ty.as_type().filter(|ty| ty.is_fn())
4222 && let fn_sig @ ty::FnSig {
4223 abi: ExternAbi::Rust,
4224 c_variadic: false,
4225 safety: hir::Safety::Safe,
4226 ..
4227 } = fn_ty.fn_sig(tcx).skip_binder()
4228
4229 && let Some(&ty::Ref(_, target_ty, needs_mut)) = fn_sig.inputs().first().map(|t| t.kind())
4231 && !target_ty.has_escaping_bound_vars()
4232
4233 && let Some(ty::Tuple(tys)) = found_ty.as_type().map(Ty::kind)
4235 && let &[found_ty] = tys.as_slice()
4236 && !found_ty.has_escaping_bound_vars()
4237
4238 && let Some(deref_target_did) = tcx.lang_items().deref_target()
4240 && let projection = Ty::new_projection_from_args(tcx,deref_target_did, tcx.mk_args(&[ty::GenericArg::from(found_ty)]))
4241 && let InferOk { value: deref_target, obligations } = infcx.at(&ObligationCause::dummy(), param_env).normalize(projection)
4242 && obligations.iter().all(|obligation| infcx.predicate_must_hold_modulo_regions(obligation))
4243 && infcx.can_eq(param_env, deref_target, target_ty)
4244 {
4245 let help = if let hir::Mutability::Mut = needs_mut
4246 && let Some(deref_mut_did) = tcx.lang_items().deref_mut_trait()
4247 && infcx
4248 .type_implements_trait(deref_mut_did, iter::once(found_ty), param_env)
4249 .must_apply_modulo_regions()
4250 {
4251 Some(("call `Option::as_deref_mut()` first", ".as_deref_mut()"))
4252 } else if let hir::Mutability::Not = needs_mut {
4253 Some(("call `Option::as_deref()` first", ".as_deref()"))
4254 } else {
4255 None
4256 };
4257
4258 if let Some((msg, sugg)) = help {
4259 err.span_suggestion_with_style(
4260 expr.span.shrink_to_hi(),
4261 msg,
4262 sugg,
4263 Applicability::MaybeIncorrect,
4264 SuggestionStyle::ShowAlways,
4265 );
4266 }
4267 }
4268 }
4269
4270 fn look_for_iterator_item_mistakes<G: EmissionGuarantee>(
4271 &self,
4272 assocs_in_this_method: &[Option<(Span, (DefId, Ty<'tcx>))>],
4273 typeck_results: &TypeckResults<'tcx>,
4274 type_diffs: &[TypeError<'tcx>],
4275 param_env: ty::ParamEnv<'tcx>,
4276 path_segment: &hir::PathSegment<'_>,
4277 args: &[hir::Expr<'_>],
4278 err: &mut Diag<'_, G>,
4279 ) {
4280 let tcx = self.tcx;
4281 for entry in assocs_in_this_method {
4284 let Some((_span, (def_id, ty))) = entry else {
4285 continue;
4286 };
4287 for diff in type_diffs {
4288 let TypeError::Sorts(expected_found) = diff else {
4289 continue;
4290 };
4291 if tcx.is_diagnostic_item(sym::IteratorItem, *def_id)
4292 && path_segment.ident.name == sym::map
4293 && self.can_eq(param_env, expected_found.found, *ty)
4294 && let [arg] = args
4295 && let hir::ExprKind::Closure(closure) = arg.kind
4296 {
4297 let body = tcx.hir_body(closure.body);
4298 if let hir::ExprKind::Block(block, None) = body.value.kind
4299 && let None = block.expr
4300 && let [.., stmt] = block.stmts
4301 && let hir::StmtKind::Semi(expr) = stmt.kind
4302 && expected_found.found.is_unit()
4306 && expr.span.hi() != stmt.span.hi()
4311 {
4312 err.span_suggestion_verbose(
4313 expr.span.shrink_to_hi().with_hi(stmt.span.hi()),
4314 "consider removing this semicolon",
4315 String::new(),
4316 Applicability::MachineApplicable,
4317 );
4318 }
4319 let expr = if let hir::ExprKind::Block(block, None) = body.value.kind
4320 && let Some(expr) = block.expr
4321 {
4322 expr
4323 } else {
4324 body.value
4325 };
4326 if let hir::ExprKind::MethodCall(path_segment, rcvr, [], span) = expr.kind
4327 && path_segment.ident.name == sym::clone
4328 && let Some(expr_ty) = typeck_results.expr_ty_opt(expr)
4329 && let Some(rcvr_ty) = typeck_results.expr_ty_opt(rcvr)
4330 && self.can_eq(param_env, expr_ty, rcvr_ty)
4331 && let ty::Ref(_, ty, _) = expr_ty.kind()
4332 {
4333 err.span_label(
4334 span,
4335 format!(
4336 "this method call is cloning the reference `{expr_ty}`, not \
4337 `{ty}` which doesn't implement `Clone`",
4338 ),
4339 );
4340 let ty::Param(..) = ty.kind() else {
4341 continue;
4342 };
4343 let node =
4344 tcx.hir_node_by_def_id(tcx.hir_get_parent_item(expr.hir_id).def_id);
4345
4346 let pred = ty::Binder::dummy(ty::TraitPredicate {
4347 trait_ref: ty::TraitRef::new(
4348 tcx,
4349 tcx.require_lang_item(LangItem::Clone, span),
4350 [*ty],
4351 ),
4352 polarity: ty::PredicatePolarity::Positive,
4353 });
4354 let Some(generics) = node.generics() else {
4355 continue;
4356 };
4357 let Some(body_id) = node.body_id() else {
4358 continue;
4359 };
4360 suggest_restriction(
4361 tcx,
4362 tcx.hir_body_owner_def_id(body_id),
4363 generics,
4364 &format!("type parameter `{ty}`"),
4365 err,
4366 node.fn_sig(),
4367 None,
4368 pred,
4369 None,
4370 );
4371 }
4372 }
4373 }
4374 }
4375 }
4376
4377 fn point_at_chain<G: EmissionGuarantee>(
4378 &self,
4379 expr: &hir::Expr<'_>,
4380 typeck_results: &TypeckResults<'tcx>,
4381 type_diffs: Vec<TypeError<'tcx>>,
4382 param_env: ty::ParamEnv<'tcx>,
4383 err: &mut Diag<'_, G>,
4384 ) {
4385 let mut primary_spans = vec![];
4386 let mut span_labels = vec![];
4387
4388 let tcx = self.tcx;
4389
4390 let mut print_root_expr = true;
4391 let mut assocs = vec![];
4392 let mut expr = expr;
4393 let mut prev_ty = self.resolve_vars_if_possible(
4394 typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
4395 );
4396 while let hir::ExprKind::MethodCall(path_segment, rcvr_expr, args, span) = expr.kind {
4397 expr = rcvr_expr;
4401 let assocs_in_this_method =
4402 self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env);
4403 self.look_for_iterator_item_mistakes(
4404 &assocs_in_this_method,
4405 typeck_results,
4406 &type_diffs,
4407 param_env,
4408 path_segment,
4409 args,
4410 err,
4411 );
4412 assocs.push(assocs_in_this_method);
4413 prev_ty = self.resolve_vars_if_possible(
4414 typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
4415 );
4416
4417 if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
4418 && let hir::Path { res: Res::Local(hir_id), .. } = path
4419 && let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id)
4420 {
4421 let parent = self.tcx.parent_hir_node(binding.hir_id);
4422 if let hir::Node::LetStmt(local) = parent
4424 && let Some(binding_expr) = local.init
4425 {
4426 expr = binding_expr;
4428 }
4429 if let hir::Node::Param(param) = parent {
4430 let prev_ty = self.resolve_vars_if_possible(
4432 typeck_results
4433 .node_type_opt(param.hir_id)
4434 .unwrap_or(Ty::new_misc_error(tcx)),
4435 );
4436 let assocs_in_this_method = self.probe_assoc_types_at_expr(
4437 &type_diffs,
4438 param.ty_span,
4439 prev_ty,
4440 param.hir_id,
4441 param_env,
4442 );
4443 if assocs_in_this_method.iter().any(|a| a.is_some()) {
4444 assocs.push(assocs_in_this_method);
4445 print_root_expr = false;
4446 }
4447 break;
4448 }
4449 }
4450 }
4451 if let Some(ty) = typeck_results.expr_ty_opt(expr)
4454 && print_root_expr
4455 {
4456 let ty = with_forced_trimmed_paths!(self.ty_to_string(ty));
4457 span_labels.push((expr.span, format!("this expression has type `{ty}`")));
4461 };
4462 let mut assocs = assocs.into_iter().peekable();
4465 while let Some(assocs_in_method) = assocs.next() {
4466 let Some(prev_assoc_in_method) = assocs.peek() else {
4467 for entry in assocs_in_method {
4468 let Some((span, (assoc, ty))) = entry else {
4469 continue;
4470 };
4471 if primary_spans.is_empty()
4472 || type_diffs.iter().any(|diff| {
4473 let TypeError::Sorts(expected_found) = diff else {
4474 return false;
4475 };
4476 self.can_eq(param_env, expected_found.found, ty)
4477 })
4478 {
4479 primary_spans.push(span);
4485 }
4486 span_labels.push((
4487 span,
4488 with_forced_trimmed_paths!(format!(
4489 "`{}` is `{ty}` here",
4490 self.tcx.def_path_str(assoc),
4491 )),
4492 ));
4493 }
4494 break;
4495 };
4496 for (entry, prev_entry) in
4497 assocs_in_method.into_iter().zip(prev_assoc_in_method.into_iter())
4498 {
4499 match (entry, prev_entry) {
4500 (Some((span, (assoc, ty))), Some((_, (_, prev_ty)))) => {
4501 let ty_str = with_forced_trimmed_paths!(self.ty_to_string(ty));
4502
4503 let assoc = with_forced_trimmed_paths!(self.tcx.def_path_str(assoc));
4504 if !self.can_eq(param_env, ty, *prev_ty) {
4505 if type_diffs.iter().any(|diff| {
4506 let TypeError::Sorts(expected_found) = diff else {
4507 return false;
4508 };
4509 self.can_eq(param_env, expected_found.found, ty)
4510 }) {
4511 primary_spans.push(span);
4512 }
4513 span_labels
4514 .push((span, format!("`{assoc}` changed to `{ty_str}` here")));
4515 } else {
4516 span_labels.push((span, format!("`{assoc}` remains `{ty_str}` here")));
4517 }
4518 }
4519 (Some((span, (assoc, ty))), None) => {
4520 span_labels.push((
4521 span,
4522 with_forced_trimmed_paths!(format!(
4523 "`{}` is `{}` here",
4524 self.tcx.def_path_str(assoc),
4525 self.ty_to_string(ty),
4526 )),
4527 ));
4528 }
4529 (None, Some(_)) | (None, None) => {}
4530 }
4531 }
4532 }
4533 if !primary_spans.is_empty() {
4534 let mut multi_span: MultiSpan = primary_spans.into();
4535 for (span, label) in span_labels {
4536 multi_span.push_span_label(span, label);
4537 }
4538 err.span_note(
4539 multi_span,
4540 "the method call chain might not have had the expected associated types",
4541 );
4542 }
4543 }
4544
4545 fn probe_assoc_types_at_expr(
4546 &self,
4547 type_diffs: &[TypeError<'tcx>],
4548 span: Span,
4549 prev_ty: Ty<'tcx>,
4550 body_id: HirId,
4551 param_env: ty::ParamEnv<'tcx>,
4552 ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>> {
4553 let ocx = ObligationCtxt::new(self.infcx);
4554 let mut assocs_in_this_method = Vec::with_capacity(type_diffs.len());
4555 for diff in type_diffs {
4556 let TypeError::Sorts(expected_found) = diff else {
4557 continue;
4558 };
4559 let ty::Alias(ty::Projection, proj) = expected_found.expected.kind() else {
4560 continue;
4561 };
4562
4563 let args = GenericArgs::for_item(self.tcx, proj.def_id, |param, _| {
4567 if param.index == 0 {
4568 debug_assert_matches!(param.kind, ty::GenericParamDefKind::Type { .. });
4569 return prev_ty.into();
4570 }
4571 self.var_for_def(span, param)
4572 });
4573 let ty = self.infcx.next_ty_var(span);
4577 let projection = ty::Binder::dummy(ty::PredicateKind::Clause(
4579 ty::ClauseKind::Projection(ty::ProjectionPredicate {
4580 projection_term: ty::AliasTerm::new_from_args(self.tcx, proj.def_id, args),
4581 term: ty.into(),
4582 }),
4583 ));
4584 let body_def_id = self.tcx.hir_enclosing_body_owner(body_id);
4585 ocx.register_obligation(Obligation::misc(
4587 self.tcx,
4588 span,
4589 body_def_id,
4590 param_env,
4591 projection,
4592 ));
4593 if ocx.try_evaluate_obligations().is_empty()
4594 && let ty = self.resolve_vars_if_possible(ty)
4595 && !ty.is_ty_var()
4596 {
4597 assocs_in_this_method.push(Some((span, (proj.def_id, ty))));
4598 } else {
4599 assocs_in_this_method.push(None);
4604 }
4605 }
4606 assocs_in_this_method
4607 }
4608
4609 pub(super) fn suggest_convert_to_slice(
4613 &self,
4614 err: &mut Diag<'_>,
4615 obligation: &PredicateObligation<'tcx>,
4616 trait_pred: ty::PolyTraitPredicate<'tcx>,
4617 candidate_impls: &[ImplCandidate<'tcx>],
4618 span: Span,
4619 ) {
4620 let (ObligationCauseCode::BinOp { .. } | ObligationCauseCode::FunctionArg { .. }) =
4623 obligation.cause.code()
4624 else {
4625 return;
4626 };
4627
4628 let (element_ty, mut mutability) = match *trait_pred.skip_binder().self_ty().kind() {
4633 ty::Array(element_ty, _) => (element_ty, None),
4634
4635 ty::Ref(_, pointee_ty, mutability) => match *pointee_ty.kind() {
4636 ty::Array(element_ty, _) => (element_ty, Some(mutability)),
4637 _ => return,
4638 },
4639
4640 _ => return,
4641 };
4642
4643 let mut is_slice = |candidate: Ty<'tcx>| match *candidate.kind() {
4646 ty::RawPtr(t, m) | ty::Ref(_, t, m) => {
4647 if matches!(*t.kind(), ty::Slice(e) if e == element_ty)
4648 && m == mutability.unwrap_or(m)
4649 {
4650 mutability = Some(m);
4652 true
4653 } else {
4654 false
4655 }
4656 }
4657 _ => false,
4658 };
4659
4660 if let Some(slice_ty) = candidate_impls
4662 .iter()
4663 .map(|trait_ref| trait_ref.trait_ref.self_ty())
4664 .find(|t| is_slice(*t))
4665 {
4666 let msg = format!("convert the array to a `{slice_ty}` slice instead");
4667
4668 if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
4669 let mut suggestions = vec![];
4670 if snippet.starts_with('&') {
4671 } else if let Some(hir::Mutability::Mut) = mutability {
4672 suggestions.push((span.shrink_to_lo(), "&mut ".into()));
4673 } else {
4674 suggestions.push((span.shrink_to_lo(), "&".into()));
4675 }
4676 suggestions.push((span.shrink_to_hi(), "[..]".into()));
4677 err.multipart_suggestion_verbose(msg, suggestions, Applicability::MaybeIncorrect);
4678 } else {
4679 err.span_help(span, msg);
4680 }
4681 }
4682 }
4683
4684 pub(super) fn suggest_tuple_wrapping(
4689 &self,
4690 err: &mut Diag<'_>,
4691 root_obligation: &PredicateObligation<'tcx>,
4692 obligation: &PredicateObligation<'tcx>,
4693 ) {
4694 let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code() else {
4695 return;
4696 };
4697
4698 let Some(root_pred) = root_obligation.predicate.as_trait_clause() else { return };
4699
4700 let trait_ref = root_pred.map_bound(|root_pred| {
4701 root_pred.trait_ref.with_replaced_self_ty(
4702 self.tcx,
4703 Ty::new_tup(self.tcx, &[root_pred.trait_ref.self_ty()]),
4704 )
4705 });
4706
4707 let obligation =
4708 Obligation::new(self.tcx, obligation.cause.clone(), obligation.param_env, trait_ref);
4709
4710 if self.predicate_must_hold_modulo_regions(&obligation) {
4711 let arg_span = self.tcx.hir_span(*arg_hir_id);
4712 err.multipart_suggestion_verbose(
4713 format!("use a unary tuple instead"),
4714 vec![(arg_span.shrink_to_lo(), "(".into()), (arg_span.shrink_to_hi(), ",)".into())],
4715 Applicability::MaybeIncorrect,
4716 );
4717 }
4718 }
4719
4720 pub(super) fn explain_hrtb_projection(
4721 &self,
4722 diag: &mut Diag<'_>,
4723 pred: ty::PolyTraitPredicate<'tcx>,
4724 param_env: ty::ParamEnv<'tcx>,
4725 cause: &ObligationCause<'tcx>,
4726 ) {
4727 if pred.skip_binder().has_escaping_bound_vars() && pred.skip_binder().has_non_region_infer()
4728 {
4729 self.probe(|_| {
4730 let ocx = ObligationCtxt::new(self);
4731 self.enter_forall(pred, |pred| {
4732 let pred = ocx.normalize(&ObligationCause::dummy(), param_env, pred);
4733 ocx.register_obligation(Obligation::new(
4734 self.tcx,
4735 ObligationCause::dummy(),
4736 param_env,
4737 pred,
4738 ));
4739 });
4740 if !ocx.try_evaluate_obligations().is_empty() {
4741 return;
4743 }
4744
4745 if let ObligationCauseCode::FunctionArg {
4746 call_hir_id,
4747 arg_hir_id,
4748 parent_code: _,
4749 } = cause.code()
4750 {
4751 let arg_span = self.tcx.hir_span(*arg_hir_id);
4752 let mut sp: MultiSpan = arg_span.into();
4753
4754 sp.push_span_label(
4755 arg_span,
4756 "the trait solver is unable to infer the \
4757 generic types that should be inferred from this argument",
4758 );
4759 sp.push_span_label(
4760 self.tcx.hir_span(*call_hir_id),
4761 "add turbofish arguments to this call to \
4762 specify the types manually, even if it's redundant",
4763 );
4764 diag.span_note(
4765 sp,
4766 "this is a known limitation of the trait solver that \
4767 will be lifted in the future",
4768 );
4769 } else {
4770 let mut sp: MultiSpan = cause.span.into();
4771 sp.push_span_label(
4772 cause.span,
4773 "try adding turbofish arguments to this expression to \
4774 specify the types manually, even if it's redundant",
4775 );
4776 diag.span_note(
4777 sp,
4778 "this is a known limitation of the trait solver that \
4779 will be lifted in the future",
4780 );
4781 }
4782 });
4783 }
4784 }
4785
4786 pub(super) fn suggest_desugaring_async_fn_in_trait(
4787 &self,
4788 err: &mut Diag<'_>,
4789 trait_pred: ty::PolyTraitPredicate<'tcx>,
4790 ) {
4791 if self.tcx.features().return_type_notation() {
4793 return;
4794 }
4795
4796 let trait_def_id = trait_pred.def_id();
4797
4798 if !self.tcx.trait_is_auto(trait_def_id) {
4800 return;
4801 }
4802
4803 let ty::Alias(ty::Projection, alias_ty) = trait_pred.self_ty().skip_binder().kind() else {
4805 return;
4806 };
4807 let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) =
4808 self.tcx.opt_rpitit_info(alias_ty.def_id)
4809 else {
4810 return;
4811 };
4812
4813 let auto_trait = self.tcx.def_path_str(trait_def_id);
4814 let Some(fn_def_id) = fn_def_id.as_local() else {
4816 if self.tcx.asyncness(fn_def_id).is_async() {
4818 err.span_note(
4819 self.tcx.def_span(fn_def_id),
4820 format!(
4821 "`{}::{}` is an `async fn` in trait, which does not \
4822 automatically imply that its future is `{auto_trait}`",
4823 alias_ty.trait_ref(self.tcx),
4824 self.tcx.item_name(fn_def_id)
4825 ),
4826 );
4827 }
4828 return;
4829 };
4830 let hir::Node::TraitItem(item) = self.tcx.hir_node_by_def_id(fn_def_id) else {
4831 return;
4832 };
4833
4834 let (sig, body) = item.expect_fn();
4836 let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(opaq_def, ..), .. }) =
4837 sig.decl.output
4838 else {
4839 return;
4841 };
4842
4843 if opaq_def.def_id.to_def_id() != opaque_def_id {
4846 return;
4847 }
4848
4849 let Some(sugg) = suggest_desugaring_async_fn_to_impl_future_in_trait(
4850 self.tcx,
4851 *sig,
4852 *body,
4853 opaque_def_id.expect_local(),
4854 &format!(" + {auto_trait}"),
4855 ) else {
4856 return;
4857 };
4858
4859 let function_name = self.tcx.def_path_str(fn_def_id);
4860 err.multipart_suggestion(
4861 format!(
4862 "`{auto_trait}` can be made part of the associated future's \
4863 guarantees for all implementations of `{function_name}`"
4864 ),
4865 sugg,
4866 Applicability::MachineApplicable,
4867 );
4868 }
4869
4870 pub fn ty_kind_suggestion(
4871 &self,
4872 param_env: ty::ParamEnv<'tcx>,
4873 ty: Ty<'tcx>,
4874 ) -> Option<String> {
4875 let tcx = self.infcx.tcx;
4876 let implements_default = |ty| {
4877 let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
4878 return false;
4879 };
4880 self.type_implements_trait(default_trait, [ty], param_env).must_apply_modulo_regions()
4881 };
4882
4883 Some(match *ty.kind() {
4884 ty::Never | ty::Error(_) => return None,
4885 ty::Bool => "false".to_string(),
4886 ty::Char => "\'x\'".to_string(),
4887 ty::Int(_) | ty::Uint(_) => "42".into(),
4888 ty::Float(_) => "3.14159".into(),
4889 ty::Slice(_) => "[]".to_string(),
4890 ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => {
4891 "vec![]".to_string()
4892 }
4893 ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::String) => {
4894 "String::new()".to_string()
4895 }
4896 ty::Adt(def, args) if def.is_box() => {
4897 format!("Box::new({})", self.ty_kind_suggestion(param_env, args[0].expect_ty())?)
4898 }
4899 ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Option) => {
4900 "None".to_string()
4901 }
4902 ty::Adt(def, args) if Some(def.did()) == tcx.get_diagnostic_item(sym::Result) => {
4903 format!("Ok({})", self.ty_kind_suggestion(param_env, args[0].expect_ty())?)
4904 }
4905 ty::Adt(_, _) if implements_default(ty) => "Default::default()".to_string(),
4906 ty::Ref(_, ty, mutability) => {
4907 if let (ty::Str, hir::Mutability::Not) = (ty.kind(), mutability) {
4908 "\"\"".to_string()
4909 } else {
4910 let ty = self.ty_kind_suggestion(param_env, ty)?;
4911 format!("&{}{ty}", mutability.prefix_str())
4912 }
4913 }
4914 ty::Array(ty, len) if let Some(len) = len.try_to_target_usize(tcx) => {
4915 if len == 0 {
4916 "[]".to_string()
4917 } else if self.type_is_copy_modulo_regions(param_env, ty) || len == 1 {
4918 format!("[{}; {}]", self.ty_kind_suggestion(param_env, ty)?, len)
4920 } else {
4921 "/* value */".to_string()
4922 }
4923 }
4924 ty::Tuple(tys) => format!(
4925 "({}{})",
4926 tys.iter()
4927 .map(|ty| self.ty_kind_suggestion(param_env, ty))
4928 .collect::<Option<Vec<String>>>()?
4929 .join(", "),
4930 if tys.len() == 1 { "," } else { "" }
4931 ),
4932 _ => "/* value */".to_string(),
4933 })
4934 }
4935
4936 pub(super) fn suggest_add_result_as_return_type(
4940 &self,
4941 obligation: &PredicateObligation<'tcx>,
4942 err: &mut Diag<'_>,
4943 trait_pred: ty::PolyTraitPredicate<'tcx>,
4944 ) {
4945 if ObligationCauseCode::QuestionMark != *obligation.cause.code().peel_derives() {
4946 return;
4947 }
4948
4949 fn choose_suggest_items<'tcx, 'hir>(
4956 tcx: TyCtxt<'tcx>,
4957 node: hir::Node<'hir>,
4958 ) -> Option<(&'hir hir::FnDecl<'hir>, hir::BodyId)> {
4959 match node {
4960 hir::Node::Item(item)
4961 if let hir::ItemKind::Fn { sig, body: body_id, .. } = item.kind =>
4962 {
4963 Some((sig.decl, body_id))
4964 }
4965 hir::Node::ImplItem(item)
4966 if let hir::ImplItemKind::Fn(sig, body_id) = item.kind =>
4967 {
4968 let parent = tcx.parent_hir_node(item.hir_id());
4969 if let hir::Node::Item(item) = parent
4970 && let hir::ItemKind::Impl(imp) = item.kind
4971 && imp.of_trait.is_none()
4972 {
4973 return Some((sig.decl, body_id));
4974 }
4975 None
4976 }
4977 _ => None,
4978 }
4979 }
4980
4981 let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id);
4982 if let Some((fn_decl, body_id)) = choose_suggest_items(self.tcx, node)
4983 && let hir::FnRetTy::DefaultReturn(ret_span) = fn_decl.output
4984 && self.tcx.is_diagnostic_item(sym::FromResidual, trait_pred.def_id())
4985 && trait_pred.skip_binder().trait_ref.args.type_at(0).is_unit()
4986 && let ty::Adt(def, _) = trait_pred.skip_binder().trait_ref.args.type_at(1).kind()
4987 && self.tcx.is_diagnostic_item(sym::Result, def.did())
4988 {
4989 let mut sugg_spans =
4990 vec![(ret_span, " -> Result<(), Box<dyn std::error::Error>>".to_string())];
4991 let body = self.tcx.hir_body(body_id);
4992 if let hir::ExprKind::Block(b, _) = body.value.kind
4993 && b.expr.is_none()
4994 {
4995 let span = self.tcx.sess.source_map().end_point(b.span);
4997 sugg_spans.push((
4998 span.shrink_to_lo(),
4999 format!(
5000 "{}{}",
5001 " Ok(())\n",
5002 self.tcx.sess.source_map().indentation_before(span).unwrap_or_default(),
5003 ),
5004 ));
5005 }
5006 err.multipart_suggestion_verbose(
5007 format!("consider adding return type"),
5008 sugg_spans,
5009 Applicability::MaybeIncorrect,
5010 );
5011 }
5012 }
5013
5014 #[instrument(level = "debug", skip_all)]
5015 pub(super) fn suggest_unsized_bound_if_applicable(
5016 &self,
5017 err: &mut Diag<'_>,
5018 obligation: &PredicateObligation<'tcx>,
5019 ) {
5020 let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
5021 obligation.predicate.kind().skip_binder()
5022 else {
5023 return;
5024 };
5025 let (ObligationCauseCode::WhereClause(item_def_id, span)
5026 | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)) =
5027 *obligation.cause.code().peel_derives()
5028 else {
5029 return;
5030 };
5031 if span.is_dummy() {
5032 return;
5033 }
5034 debug!(?pred, ?item_def_id, ?span);
5035
5036 let (Some(node), true) = (
5037 self.tcx.hir_get_if_local(item_def_id),
5038 self.tcx.is_lang_item(pred.def_id(), LangItem::Sized),
5039 ) else {
5040 return;
5041 };
5042
5043 let Some(generics) = node.generics() else {
5044 return;
5045 };
5046 let sized_trait = self.tcx.lang_items().sized_trait();
5047 debug!(?generics.params);
5048 debug!(?generics.predicates);
5049 let Some(param) = generics.params.iter().find(|param| param.span == span) else {
5050 return;
5051 };
5052 let explicitly_sized = generics
5055 .bounds_for_param(param.def_id)
5056 .flat_map(|bp| bp.bounds)
5057 .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait);
5058 if explicitly_sized {
5059 return;
5060 }
5061 debug!(?param);
5062 match node {
5063 hir::Node::Item(
5064 item @ hir::Item {
5065 kind:
5067 hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..),
5068 ..
5069 },
5070 ) => {
5071 if self.suggest_indirection_for_unsized(err, item, param) {
5072 return;
5073 }
5074 }
5075 _ => {}
5076 };
5077
5078 let (span, separator, open_paren_sp) =
5080 if let Some((s, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) {
5081 (s, " +", open_paren_sp)
5082 } else {
5083 (param.name.ident().span.shrink_to_hi(), ":", None)
5084 };
5085
5086 let mut suggs = vec![];
5087 let suggestion = format!("{separator} ?Sized");
5088
5089 if let Some(open_paren_sp) = open_paren_sp {
5090 suggs.push((open_paren_sp, "(".to_string()));
5091 suggs.push((span, format!("){suggestion}")));
5092 } else {
5093 suggs.push((span, suggestion));
5094 }
5095
5096 err.multipart_suggestion_verbose(
5097 "consider relaxing the implicit `Sized` restriction",
5098 suggs,
5099 Applicability::MachineApplicable,
5100 );
5101 }
5102
5103 fn suggest_indirection_for_unsized(
5104 &self,
5105 err: &mut Diag<'_>,
5106 item: &hir::Item<'tcx>,
5107 param: &hir::GenericParam<'tcx>,
5108 ) -> bool {
5109 let mut visitor = FindTypeParam { param: param.name.ident().name, .. };
5113 visitor.visit_item(item);
5114 if visitor.invalid_spans.is_empty() {
5115 return false;
5116 }
5117 let mut multispan: MultiSpan = param.span.into();
5118 multispan.push_span_label(
5119 param.span,
5120 format!("this could be changed to `{}: ?Sized`...", param.name.ident()),
5121 );
5122 for sp in visitor.invalid_spans {
5123 multispan.push_span_label(
5124 sp,
5125 format!("...if indirection were used here: `Box<{}>`", param.name.ident()),
5126 );
5127 }
5128 err.span_help(
5129 multispan,
5130 format!(
5131 "you could relax the implicit `Sized` bound on `{T}` if it were \
5132 used through indirection like `&{T}` or `Box<{T}>`",
5133 T = param.name.ident(),
5134 ),
5135 );
5136 true
5137 }
5138 pub(crate) fn suggest_swapping_lhs_and_rhs<T>(
5139 &self,
5140 err: &mut Diag<'_>,
5141 predicate: T,
5142 param_env: ty::ParamEnv<'tcx>,
5143 cause_code: &ObligationCauseCode<'tcx>,
5144 ) where
5145 T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
5146 {
5147 let tcx = self.tcx;
5148 let predicate = predicate.upcast(tcx);
5149 match *cause_code {
5150 ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, rhs_span, .. }
5151 if let Some(typeck_results) = &self.typeck_results
5152 && let hir::Node::Expr(lhs) = tcx.hir_node(lhs_hir_id)
5153 && let hir::Node::Expr(rhs) = tcx.hir_node(rhs_hir_id)
5154 && let Some(lhs_ty) = typeck_results.expr_ty_opt(lhs)
5155 && let Some(rhs_ty) = typeck_results.expr_ty_opt(rhs) =>
5156 {
5157 if let Some(pred) = predicate.as_trait_clause()
5158 && tcx.is_lang_item(pred.def_id(), LangItem::PartialEq)
5159 && self
5160 .infcx
5161 .type_implements_trait(pred.def_id(), [rhs_ty, lhs_ty], param_env)
5162 .must_apply_modulo_regions()
5163 {
5164 let lhs_span = tcx.hir_span(lhs_hir_id);
5165 let sm = tcx.sess.source_map();
5166 if let Ok(rhs_snippet) = sm.span_to_snippet(rhs_span)
5167 && let Ok(lhs_snippet) = sm.span_to_snippet(lhs_span)
5168 {
5169 err.note(format!("`{rhs_ty}` implements `PartialEq<{lhs_ty}>`"));
5170 err.multipart_suggestion(
5171 "consider swapping the equality",
5172 vec![(lhs_span, rhs_snippet), (rhs_span, lhs_snippet)],
5173 Applicability::MaybeIncorrect,
5174 );
5175 }
5176 }
5177 }
5178 _ => {}
5179 }
5180 }
5181}
5182
5183fn hint_missing_borrow<'tcx>(
5185 infcx: &InferCtxt<'tcx>,
5186 param_env: ty::ParamEnv<'tcx>,
5187 span: Span,
5188 found: Ty<'tcx>,
5189 expected: Ty<'tcx>,
5190 found_node: Node<'_>,
5191 err: &mut Diag<'_>,
5192) {
5193 if matches!(found_node, Node::TraitItem(..)) {
5194 return;
5195 }
5196
5197 let found_args = match found.kind() {
5198 ty::FnPtr(sig_tys, _) => infcx.enter_forall(*sig_tys, |sig_tys| sig_tys.inputs().iter()),
5199 kind => {
5200 span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
5201 }
5202 };
5203 let expected_args = match expected.kind() {
5204 ty::FnPtr(sig_tys, _) => infcx.enter_forall(*sig_tys, |sig_tys| sig_tys.inputs().iter()),
5205 kind => {
5206 span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind)
5207 }
5208 };
5209
5210 let Some(fn_decl) = found_node.fn_decl() else {
5212 return;
5213 };
5214
5215 let args = fn_decl.inputs.iter();
5216
5217 let mut to_borrow = Vec::new();
5218 let mut remove_borrow = Vec::new();
5219
5220 for ((found_arg, expected_arg), arg) in found_args.zip(expected_args).zip(args) {
5221 let (found_ty, found_refs) = get_deref_type_and_refs(*found_arg);
5222 let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg);
5223
5224 if infcx.can_eq(param_env, found_ty, expected_ty) {
5225 if found_refs.len() < expected_refs.len()
5227 && found_refs[..] == expected_refs[expected_refs.len() - found_refs.len()..]
5228 {
5229 to_borrow.push((
5230 arg.span.shrink_to_lo(),
5231 expected_refs[..expected_refs.len() - found_refs.len()]
5232 .iter()
5233 .map(|mutbl| format!("&{}", mutbl.prefix_str()))
5234 .collect::<Vec<_>>()
5235 .join(""),
5236 ));
5237 } else if found_refs.len() > expected_refs.len() {
5238 let mut span = arg.span.shrink_to_lo();
5239 let mut left = found_refs.len() - expected_refs.len();
5240 let mut ty = arg;
5241 while let hir::TyKind::Ref(_, mut_ty) = &ty.kind
5242 && left > 0
5243 {
5244 span = span.with_hi(mut_ty.ty.span.lo());
5245 ty = mut_ty.ty;
5246 left -= 1;
5247 }
5248 let sugg = if left == 0 {
5249 (span, String::new())
5250 } else {
5251 (arg.span, expected_arg.to_string())
5252 };
5253 remove_borrow.push(sugg);
5254 }
5255 }
5256 }
5257
5258 if !to_borrow.is_empty() {
5259 err.subdiagnostic(errors::AdjustSignatureBorrow::Borrow { to_borrow });
5260 }
5261
5262 if !remove_borrow.is_empty() {
5263 err.subdiagnostic(errors::AdjustSignatureBorrow::RemoveBorrow { remove_borrow });
5264 }
5265}
5266
5267#[derive(Debug)]
5270pub struct SelfVisitor<'v> {
5271 pub paths: Vec<&'v hir::Ty<'v>> = Vec::new(),
5272 pub name: Option<Symbol>,
5273}
5274
5275impl<'v> Visitor<'v> for SelfVisitor<'v> {
5276 fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
5277 if let hir::TyKind::Path(path) = ty.kind
5278 && let hir::QPath::TypeRelative(inner_ty, segment) = path
5279 && (Some(segment.ident.name) == self.name || self.name.is_none())
5280 && let hir::TyKind::Path(inner_path) = inner_ty.kind
5281 && let hir::QPath::Resolved(None, inner_path) = inner_path
5282 && let Res::SelfTyAlias { .. } = inner_path.res
5283 {
5284 self.paths.push(ty.as_unambig_ty());
5285 }
5286 hir::intravisit::walk_ty(self, ty);
5287 }
5288}
5289
5290#[derive(Default)]
5293pub struct ReturnsVisitor<'v> {
5294 pub returns: Vec<&'v hir::Expr<'v>>,
5295 in_block_tail: bool,
5296}
5297
5298impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
5299 fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
5300 match ex.kind {
5305 hir::ExprKind::Ret(Some(ex)) => {
5306 self.returns.push(ex);
5307 }
5308 hir::ExprKind::Block(block, _) if self.in_block_tail => {
5309 self.in_block_tail = false;
5310 for stmt in block.stmts {
5311 hir::intravisit::walk_stmt(self, stmt);
5312 }
5313 self.in_block_tail = true;
5314 if let Some(expr) = block.expr {
5315 self.visit_expr(expr);
5316 }
5317 }
5318 hir::ExprKind::If(_, then, else_opt) if self.in_block_tail => {
5319 self.visit_expr(then);
5320 if let Some(el) = else_opt {
5321 self.visit_expr(el);
5322 }
5323 }
5324 hir::ExprKind::Match(_, arms, _) if self.in_block_tail => {
5325 for arm in arms {
5326 self.visit_expr(arm.body);
5327 }
5328 }
5329 _ if !self.in_block_tail => hir::intravisit::walk_expr(self, ex),
5331 _ => self.returns.push(ex),
5332 }
5333 }
5334
5335 fn visit_body(&mut self, body: &hir::Body<'v>) {
5336 assert!(!self.in_block_tail);
5337 self.in_block_tail = true;
5338 hir::intravisit::walk_body(self, body);
5339 }
5340}
5341
5342#[derive(Default)]
5344struct AwaitsVisitor {
5345 awaits: Vec<HirId>,
5346}
5347
5348impl<'v> Visitor<'v> for AwaitsVisitor {
5349 fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
5350 if let hir::ExprKind::Yield(_, hir::YieldSource::Await { expr: Some(id) }) = ex.kind {
5351 self.awaits.push(id)
5352 }
5353 hir::intravisit::walk_expr(self, ex)
5354 }
5355}
5356
5357pub trait NextTypeParamName {
5361 fn next_type_param_name(&self, name: Option<&str>) -> String;
5362}
5363
5364impl NextTypeParamName for &[hir::GenericParam<'_>] {
5365 fn next_type_param_name(&self, name: Option<&str>) -> String {
5366 let name = name.and_then(|n| n.chars().next()).map(|c| c.to_uppercase().to_string());
5368 let name = name.as_deref();
5369
5370 let possible_names = [name.unwrap_or("T"), "T", "U", "V", "X", "Y", "Z", "A", "B", "C"];
5372
5373 let used_names: Vec<Symbol> = self
5375 .iter()
5376 .filter_map(|param| match param.name {
5377 hir::ParamName::Plain(ident) => Some(ident.name),
5378 _ => None,
5379 })
5380 .collect();
5381
5382 possible_names
5384 .iter()
5385 .find(|n| !used_names.contains(&Symbol::intern(n)))
5386 .unwrap_or(&"ParamName")
5387 .to_string()
5388 }
5389}
5390
5391struct ReplaceImplTraitVisitor<'a> {
5393 ty_spans: &'a mut Vec<Span>,
5394 param_did: DefId,
5395}
5396
5397impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> {
5398 fn visit_ty(&mut self, t: &'hir hir::Ty<'hir, AmbigArg>) {
5399 if let hir::TyKind::Path(hir::QPath::Resolved(
5400 None,
5401 hir::Path { res: Res::Def(_, segment_did), .. },
5402 )) = t.kind
5403 {
5404 if self.param_did == *segment_did {
5405 self.ty_spans.push(t.span);
5410 return;
5411 }
5412 }
5413
5414 hir::intravisit::walk_ty(self, t);
5415 }
5416}
5417
5418pub(super) fn get_explanation_based_on_obligation<'tcx>(
5419 tcx: TyCtxt<'tcx>,
5420 obligation: &PredicateObligation<'tcx>,
5421 trait_predicate: ty::PolyTraitPredicate<'tcx>,
5422 pre_message: String,
5423 long_ty_path: &mut Option<PathBuf>,
5424) -> String {
5425 if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
5426 "consider using `()`, or a `Result`".to_owned()
5427 } else {
5428 let ty_desc = match trait_predicate.self_ty().skip_binder().kind() {
5429 ty::FnDef(_, _) => Some("fn item"),
5430 ty::Closure(_, _) => Some("closure"),
5431 _ => None,
5432 };
5433
5434 let desc = match ty_desc {
5435 Some(desc) => format!(" {desc}"),
5436 None => String::new(),
5437 };
5438 if let ty::PredicatePolarity::Positive = trait_predicate.polarity() {
5439 format!(
5440 "{pre_message}the trait `{}` is not implemented for{desc} `{}`",
5441 trait_predicate.print_modifiers_and_trait_path(),
5442 tcx.short_string(trait_predicate.self_ty().skip_binder(), long_ty_path),
5443 )
5444 } else {
5445 format!("{pre_message}the trait bound `{trait_predicate}` is not satisfied")
5449 }
5450 }
5451}
5452
5453struct ReplaceImplTraitFolder<'tcx> {
5455 tcx: TyCtxt<'tcx>,
5456 param: &'tcx ty::GenericParamDef,
5457 replace_ty: Ty<'tcx>,
5458}
5459
5460impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceImplTraitFolder<'tcx> {
5461 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
5462 if let ty::Param(ty::ParamTy { index, .. }) = t.kind() {
5463 if self.param.index == *index {
5464 return self.replace_ty;
5465 }
5466 }
5467 t.super_fold_with(self)
5468 }
5469
5470 fn cx(&self) -> TyCtxt<'tcx> {
5471 self.tcx
5472 }
5473}
5474
5475pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>(
5476 tcx: TyCtxt<'tcx>,
5477 sig: hir::FnSig<'tcx>,
5478 body: hir::TraitFn<'tcx>,
5479 opaque_def_id: LocalDefId,
5480 add_bounds: &str,
5481) -> Option<Vec<(Span, String)>> {
5482 let hir::IsAsync::Async(async_span) = sig.header.asyncness else {
5483 return None;
5484 };
5485 let async_span = tcx.sess.source_map().span_extend_while_whitespace(async_span);
5486
5487 let future = tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty();
5488 let [hir::GenericBound::Trait(trait_ref)] = future.bounds else {
5489 return None;
5491 };
5492 let Some(hir::PathSegment { args: Some(args), .. }) = trait_ref.trait_ref.path.segments.last()
5493 else {
5494 return None;
5496 };
5497 let Some(future_output_ty) = args.constraints.first().and_then(|constraint| constraint.ty())
5498 else {
5499 return None;
5501 };
5502
5503 let mut sugg = if future_output_ty.span.is_empty() {
5504 vec![
5505 (async_span, String::new()),
5506 (
5507 future_output_ty.span,
5508 format!(" -> impl std::future::Future<Output = ()>{add_bounds}"),
5509 ),
5510 ]
5511 } else {
5512 vec![
5513 (future_output_ty.span.shrink_to_lo(), "impl std::future::Future<Output = ".to_owned()),
5514 (future_output_ty.span.shrink_to_hi(), format!(">{add_bounds}")),
5515 (async_span, String::new()),
5516 ]
5517 };
5518
5519 if let hir::TraitFn::Provided(body) = body {
5521 let body = tcx.hir_body(body);
5522 let body_span = body.value.span;
5523 let body_span_without_braces =
5524 body_span.with_lo(body_span.lo() + BytePos(1)).with_hi(body_span.hi() - BytePos(1));
5525 if body_span_without_braces.is_empty() {
5526 sugg.push((body_span_without_braces, " async {} ".to_owned()));
5527 } else {
5528 sugg.extend([
5529 (body_span_without_braces.shrink_to_lo(), "async {".to_owned()),
5530 (body_span_without_braces.shrink_to_hi(), "} ".to_owned()),
5531 ]);
5532 }
5533 }
5534
5535 Some(sugg)
5536}
5537
5538fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
5541 tcx: TyCtxt<'_>,
5542 err: &mut Diag<'_, G>,
5543 self_ty_str: &str,
5544 trait_name: &str,
5545 predicate: ty::Predicate<'_>,
5546 generics: &hir::Generics<'_>,
5547 data: &ImplDerivedCause<'_>,
5548) {
5549 let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() else {
5550 return;
5551 };
5552 let ty::ClauseKind::Projection(proj) = clause else {
5553 return;
5554 };
5555 let name = tcx.item_name(proj.projection_term.def_id);
5556 let mut predicates = generics.predicates.iter().peekable();
5557 let mut prev: Option<(&hir::WhereBoundPredicate<'_>, Span)> = None;
5558 while let Some(pred) = predicates.next() {
5559 let curr_span = pred.span;
5560 let hir::WherePredicateKind::BoundPredicate(pred) = pred.kind else {
5561 continue;
5562 };
5563 let mut bounds = pred.bounds.iter();
5564 while let Some(bound) = bounds.next() {
5565 let Some(trait_ref) = bound.trait_ref() else {
5566 continue;
5567 };
5568 if bound.span() != data.span {
5569 continue;
5570 }
5571 if let hir::TyKind::Path(path) = pred.bounded_ty.kind
5572 && let hir::QPath::TypeRelative(ty, segment) = path
5573 && segment.ident.name == name
5574 && let hir::TyKind::Path(inner_path) = ty.kind
5575 && let hir::QPath::Resolved(None, inner_path) = inner_path
5576 && let Res::SelfTyAlias { .. } = inner_path.res
5577 {
5578 let span = if pred.origin == hir::PredicateOrigin::WhereClause
5581 && generics
5582 .predicates
5583 .iter()
5584 .filter(|p| {
5585 matches!(
5586 p.kind,
5587 hir::WherePredicateKind::BoundPredicate(p)
5588 if hir::PredicateOrigin::WhereClause == p.origin
5589 )
5590 })
5591 .count()
5592 == 1
5593 {
5594 generics.where_clause_span
5597 } else if let Some(next_pred) = predicates.peek()
5598 && let hir::WherePredicateKind::BoundPredicate(next) = next_pred.kind
5599 && pred.origin == next.origin
5600 {
5601 curr_span.until(next_pred.span)
5603 } else if let Some((prev, prev_span)) = prev
5604 && pred.origin == prev.origin
5605 {
5606 prev_span.shrink_to_hi().to(curr_span)
5608 } else if pred.origin == hir::PredicateOrigin::WhereClause {
5609 curr_span.with_hi(generics.where_clause_span.hi())
5610 } else {
5611 curr_span
5612 };
5613
5614 err.span_suggestion_verbose(
5615 span,
5616 "associated type for the current `impl` cannot be restricted in `where` \
5617 clauses, remove this bound",
5618 "",
5619 Applicability::MaybeIncorrect,
5620 );
5621 }
5622 if let Some(new) =
5623 tcx.associated_items(data.impl_or_alias_def_id).find_by_ident_and_kind(
5624 tcx,
5625 Ident::with_dummy_span(name),
5626 ty::AssocTag::Type,
5627 data.impl_or_alias_def_id,
5628 )
5629 {
5630 let span = tcx.def_span(new.def_id);
5633 err.span_label(
5634 span,
5635 format!(
5636 "associated type `<{self_ty_str} as {trait_name}>::{name}` is specified \
5637 here",
5638 ),
5639 );
5640 let mut visitor = SelfVisitor { name: Some(name), .. };
5643 visitor.visit_trait_ref(trait_ref);
5644 for path in visitor.paths {
5645 err.span_suggestion_verbose(
5646 path.span,
5647 "replace the associated type with the type specified in this `impl`",
5648 tcx.type_of(new.def_id).skip_binder(),
5649 Applicability::MachineApplicable,
5650 );
5651 }
5652 } else {
5653 let mut visitor = SelfVisitor { name: None, .. };
5654 visitor.visit_trait_ref(trait_ref);
5655 let span: MultiSpan =
5656 visitor.paths.iter().map(|p| p.span).collect::<Vec<Span>>().into();
5657 err.span_note(
5658 span,
5659 "associated types for the current `impl` cannot be restricted in `where` \
5660 clauses",
5661 );
5662 }
5663 }
5664 prev = Some((pred, curr_span));
5665 }
5666}
5667
5668fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
5669 let mut refs = vec![];
5670
5671 while let ty::Ref(_, new_ty, mutbl) = ty.kind() {
5672 ty = *new_ty;
5673 refs.push(*mutbl);
5674 }
5675
5676 (ty, refs)
5677}
5678
5679struct FindTypeParam {
5682 param: rustc_span::Symbol,
5683 invalid_spans: Vec<Span> = Vec::new(),
5684 nested: bool = false,
5685}
5686
5687impl<'v> Visitor<'v> for FindTypeParam {
5688 fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) {
5689 }
5691
5692 fn visit_ty(&mut self, ty: &hir::Ty<'_, AmbigArg>) {
5693 match ty.kind {
5700 hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {}
5701 hir::TyKind::Path(hir::QPath::Resolved(None, path))
5702 if let [segment] = path.segments
5703 && segment.ident.name == self.param =>
5704 {
5705 if !self.nested {
5706 debug!(?ty, "FindTypeParam::visit_ty");
5707 self.invalid_spans.push(ty.span);
5708 }
5709 }
5710 hir::TyKind::Path(_) => {
5711 let prev = self.nested;
5712 self.nested = true;
5713 hir::intravisit::walk_ty(self, ty);
5714 self.nested = prev;
5715 }
5716 _ => {
5717 hir::intravisit::walk_ty(self, ty);
5718 }
5719 }
5720 }
5721}
5722
5723struct ParamFinder {
5726 params: Vec<Symbol> = Vec::new(),
5727}
5728
5729impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParamFinder {
5730 fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
5731 match t.kind() {
5732 ty::Param(p) => self.params.push(p.name),
5733 _ => {}
5734 }
5735 t.super_visit_with(self)
5736 }
5737}
5738
5739impl ParamFinder {
5740 fn can_suggest_bound(&self, generics: &hir::Generics<'_>) -> bool {
5743 if self.params.is_empty() {
5744 return true;
5747 }
5748 generics.params.iter().any(|p| match p.name {
5749 hir::ParamName::Plain(p_name) => {
5750 self.params.iter().any(|p| *p == p_name.name || *p == kw::SelfUpper)
5752 }
5753 _ => true,
5754 })
5755 }
5756}