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