1use rustc_errors::{Applicability, Diag, MultiSpan, listify};
2use rustc_hir as hir;
3use rustc_hir::def::Res;
4use rustc_hir::intravisit::Visitor;
5use rustc_infer::infer::DefineOpaqueTypes;
6use rustc_middle::bug;
7use rustc_middle::ty::adjustment::AllowTwoPhase;
8use rustc_middle::ty::error::{ExpectedFound, TypeError};
9use rustc_middle::ty::fold::BottomUpFolder;
10use rustc_middle::ty::print::with_no_trimmed_paths;
11use rustc_middle::ty::{self, AssocItem, Ty, TypeFoldable, TypeVisitableExt};
12use rustc_span::{DUMMY_SP, Ident, Span, sym};
13use rustc_trait_selection::infer::InferCtxtExt;
14use rustc_trait_selection::traits::ObligationCause;
15use tracing::instrument;
16
17use super::method::probe;
18use crate::FnCtxt;
19
20impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21 pub(crate) fn emit_type_mismatch_suggestions(
22 &self,
23 err: &mut Diag<'_>,
24 expr: &hir::Expr<'tcx>,
25 expr_ty: Ty<'tcx>,
26 expected: Ty<'tcx>,
27 expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
28 error: Option<TypeError<'tcx>>,
29 ) {
30 if expr_ty == expected {
31 return;
32 }
33 self.annotate_alternative_method_deref(err, expr, error);
34 self.explain_self_literal(err, expr, expected, expr_ty);
35
36 let suggested = self.suggest_missing_parentheses(err, expr)
38 || self.suggest_missing_unwrap_expect(err, expr, expected, expr_ty)
39 || self.suggest_remove_last_method_call(err, expr, expected)
40 || self.suggest_associated_const(err, expr, expected)
41 || self.suggest_semicolon_in_repeat_expr(err, expr, expr_ty)
42 || self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr)
43 || self.suggest_option_to_bool(err, expr, expr_ty, expected)
44 || self.suggest_compatible_variants(err, expr, expected, expr_ty)
45 || self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty)
46 || self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty)
47 || self.suggest_no_capture_closure(err, expected, expr_ty)
48 || self.suggest_boxing_when_appropriate(
49 err,
50 expr.peel_blocks().span,
51 expr.hir_id,
52 expected,
53 expr_ty,
54 )
55 || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
56 || self.suggest_copied_cloned_or_as_ref(err, expr, expr_ty, expected)
57 || self.suggest_clone_for_ref(err, expr, expr_ty, expected)
58 || self.suggest_into(err, expr, expr_ty, expected)
59 || self.suggest_floating_point_literal(err, expr, expected)
60 || self.suggest_null_ptr_for_literal_zero_given_to_ptr_arg(err, expr, expected)
61 || self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty)
62 || self.suggest_returning_value_after_loop(err, expr, expected);
63
64 if !suggested {
65 self.note_source_of_type_mismatch_constraint(
66 err,
67 expr,
68 TypeMismatchSource::Ty(expected),
69 );
70 }
71 }
72
73 pub(crate) fn emit_coerce_suggestions(
74 &self,
75 err: &mut Diag<'_>,
76 expr: &hir::Expr<'tcx>,
77 expr_ty: Ty<'tcx>,
78 expected: Ty<'tcx>,
79 expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
80 error: Option<TypeError<'tcx>>,
81 ) {
82 if expr_ty == expected {
83 return;
84 }
85
86 self.annotate_expected_due_to_let_ty(err, expr, error);
87 self.annotate_loop_expected_due_to_inference(err, expr, error);
88 if self.annotate_mut_binding_to_immutable_binding(err, expr, error) {
89 return;
90 }
91
92 if matches!(error, Some(TypeError::RegionsInsufficientlyPolymorphic(..))) {
96 return;
97 }
98
99 if self.is_destruct_assignment_desugaring(expr) {
100 return;
101 }
102 self.emit_type_mismatch_suggestions(err, expr, expr_ty, expected, expected_ty_expr, error);
103 self.note_type_is_not_clone(err, expected, expr_ty, expr);
104 self.note_internal_mutation_in_method(err, expr, Some(expected), expr_ty);
105 self.suggest_method_call_on_range_literal(err, expr, expr_ty, expected);
106 self.suggest_return_binding_for_missing_tail_expr(err, expr, expr_ty, expected);
107 self.note_wrong_return_ty_due_to_generic_arg(err, expr, expr_ty);
108 }
109
110 fn adjust_expr_for_assert_eq_macro(
113 &self,
114 found_expr: &mut &'tcx hir::Expr<'tcx>,
115 expected_expr: &mut Option<&'tcx hir::Expr<'tcx>>,
116 ) {
117 let Some(expected_expr) = expected_expr else {
118 return;
119 };
120
121 if !found_expr.span.eq_ctxt(expected_expr.span) {
122 return;
123 }
124
125 if !found_expr
126 .span
127 .ctxt()
128 .outer_expn_data()
129 .macro_def_id
130 .is_some_and(|def_id| self.tcx.is_diagnostic_item(sym::assert_eq_macro, def_id))
131 {
132 return;
133 }
134
135 let hir::ExprKind::Unary(
136 hir::UnOp::Deref,
137 hir::Expr { kind: hir::ExprKind::Path(found_path), .. },
138 ) = found_expr.kind
139 else {
140 return;
141 };
142 let hir::ExprKind::Unary(
143 hir::UnOp::Deref,
144 hir::Expr { kind: hir::ExprKind::Path(expected_path), .. },
145 ) = expected_expr.kind
146 else {
147 return;
148 };
149
150 for (path, name, idx, var) in [
151 (expected_path, "left_val", 0, expected_expr),
152 (found_path, "right_val", 1, found_expr),
153 ] {
154 if let hir::QPath::Resolved(_, path) = path
155 && let [segment] = path.segments
156 && segment.ident.name.as_str() == name
157 && let Res::Local(hir_id) = path.res
158 && let Some((_, hir::Node::Expr(match_expr))) =
159 self.tcx.hir().parent_iter(hir_id).nth(2)
160 && let hir::ExprKind::Match(scrutinee, _, _) = match_expr.kind
161 && let hir::ExprKind::Tup(exprs) = scrutinee.kind
162 && let hir::ExprKind::AddrOf(_, _, macro_arg) = exprs[idx].kind
163 {
164 *var = macro_arg;
165 }
166 }
167 }
168
169 pub(crate) fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
172 if let Err(e) = self.demand_suptype_diag(sp, expected, actual) {
173 e.emit();
174 }
175 }
176
177 pub(crate) fn demand_suptype_diag(
178 &'a self,
179 sp: Span,
180 expected: Ty<'tcx>,
181 actual: Ty<'tcx>,
182 ) -> Result<(), Diag<'a>> {
183 self.demand_suptype_with_origin(&self.misc(sp), expected, actual)
184 }
185
186 #[instrument(skip(self), level = "debug")]
187 pub(crate) fn demand_suptype_with_origin(
188 &'a self,
189 cause: &ObligationCause<'tcx>,
190 expected: Ty<'tcx>,
191 actual: Ty<'tcx>,
192 ) -> Result<(), Diag<'a>> {
193 self.at(cause, self.param_env)
194 .sup(DefineOpaqueTypes::Yes, expected, actual)
195 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
196 .map_err(|e| {
197 self.err_ctxt().report_mismatched_types(cause, self.param_env, expected, actual, e)
198 })
199 }
200
201 pub(crate) fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
202 if let Err(err) = self.demand_eqtype_diag(sp, expected, actual) {
203 err.emit();
204 }
205 }
206
207 pub(crate) fn demand_eqtype_diag(
208 &'a self,
209 sp: Span,
210 expected: Ty<'tcx>,
211 actual: Ty<'tcx>,
212 ) -> Result<(), Diag<'a>> {
213 self.demand_eqtype_with_origin(&self.misc(sp), expected, actual)
214 }
215
216 pub(crate) fn demand_eqtype_with_origin(
217 &'a self,
218 cause: &ObligationCause<'tcx>,
219 expected: Ty<'tcx>,
220 actual: Ty<'tcx>,
221 ) -> Result<(), Diag<'a>> {
222 self.at(cause, self.param_env)
223 .eq(DefineOpaqueTypes::Yes, expected, actual)
224 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
225 .map_err(|e| {
226 self.err_ctxt().report_mismatched_types(cause, self.param_env, expected, actual, e)
227 })
228 }
229
230 pub(crate) fn demand_coerce(
231 &self,
232 expr: &'tcx hir::Expr<'tcx>,
233 checked_ty: Ty<'tcx>,
234 expected: Ty<'tcx>,
235 expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
236 allow_two_phase: AllowTwoPhase,
237 ) -> Ty<'tcx> {
238 match self.demand_coerce_diag(expr, checked_ty, expected, expected_ty_expr, allow_two_phase)
239 {
240 Ok(ty) => ty,
241 Err(err) => {
242 err.emit();
243 expected
247 }
248 }
249 }
250
251 #[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
256 pub(crate) fn demand_coerce_diag(
257 &'a self,
258 mut expr: &'tcx hir::Expr<'tcx>,
259 checked_ty: Ty<'tcx>,
260 expected: Ty<'tcx>,
261 mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
262 allow_two_phase: AllowTwoPhase,
263 ) -> Result<Ty<'tcx>, Diag<'a>> {
264 let expected = self.resolve_vars_with_obligations(expected);
265
266 let e = match self.coerce(expr, checked_ty, expected, allow_two_phase, None) {
267 Ok(ty) => return Ok(ty),
268 Err(e) => e,
269 };
270
271 self.adjust_expr_for_assert_eq_macro(&mut expr, &mut expected_ty_expr);
272
273 self.set_tainted_by_errors(self.dcx().span_delayed_bug(
274 expr.span,
275 "`TypeError` when attempting coercion but no error emitted",
276 ));
277 let expr = expr.peel_drop_temps();
278 let cause = self.misc(expr.span);
279 let expr_ty = self.resolve_vars_if_possible(checked_ty);
280 let mut err =
281 self.err_ctxt().report_mismatched_types(&cause, self.param_env, expected, expr_ty, e);
282
283 self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr, Some(e));
284
285 Err(err)
286 }
287
288 pub(crate) fn note_source_of_type_mismatch_constraint(
291 &self,
292 err: &mut Diag<'_>,
293 expr: &hir::Expr<'_>,
294 source: TypeMismatchSource<'tcx>,
295 ) -> bool {
296 let hir = self.tcx.hir();
297
298 let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind else {
299 return false;
300 };
301 let [hir::PathSegment { ident, args: None, .. }] = p.segments else {
302 return false;
303 };
304 let hir::def::Res::Local(local_hir_id) = p.res else {
305 return false;
306 };
307 let hir::Node::Pat(pat) = self.tcx.hir_node(local_hir_id) else {
308 return false;
309 };
310 let (init_ty_hir_id, init) = match self.tcx.parent_hir_node(pat.hir_id) {
311 hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), init, .. }) => (ty.hir_id, *init),
312 hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) => (init.hir_id, Some(*init)),
313 _ => return false,
314 };
315 let Some(init_ty) = self.node_ty_opt(init_ty_hir_id) else {
316 return false;
317 };
318
319 struct FindExprs<'tcx> {
321 hir_id: hir::HirId,
322 uses: Vec<&'tcx hir::Expr<'tcx>>,
323 }
324 impl<'tcx> Visitor<'tcx> for FindExprs<'tcx> {
325 fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
326 if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = ex.kind
327 && let hir::def::Res::Local(hir_id) = path.res
328 && hir_id == self.hir_id
329 {
330 self.uses.push(ex);
331 }
332 hir::intravisit::walk_expr(self, ex);
333 }
334 }
335
336 let mut expr_finder = FindExprs { hir_id: local_hir_id, uses: init.into_iter().collect() };
337 let body = hir.body_owned_by(self.body_id);
338 expr_finder.visit_expr(body.value);
339
340 let mut fudger = BottomUpFolder {
342 tcx: self.tcx,
343 ty_op: |ty| {
344 if let ty::Infer(infer) = ty.kind() {
345 match infer {
346 ty::TyVar(_) => self.next_ty_var(DUMMY_SP),
347 ty::IntVar(_) => self.next_int_var(),
348 ty::FloatVar(_) => self.next_float_var(),
349 ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
350 bug!("unexpected fresh ty outside of the trait solver")
351 }
352 }
353 } else {
354 ty
355 }
356 },
357 lt_op: |_| self.tcx.lifetimes.re_erased,
358 ct_op: |ct| {
359 if let ty::ConstKind::Infer(_) = ct.kind() {
360 self.next_const_var(DUMMY_SP)
361 } else {
362 ct
363 }
364 },
365 };
366
367 let expected_ty = match source {
368 TypeMismatchSource::Ty(expected_ty) => expected_ty,
369 TypeMismatchSource::Arg { call_expr, incompatible_arg: idx } => {
376 let hir::ExprKind::MethodCall(segment, _, args, _) = call_expr.kind else {
377 return false;
378 };
379 let Some(arg_ty) = self.node_ty_opt(args[idx].hir_id) else {
380 return false;
381 };
382 let possible_rcvr_ty = expr_finder.uses.iter().rev().find_map(|binding| {
383 let possible_rcvr_ty = self.node_ty_opt(binding.hir_id)?;
384 if possible_rcvr_ty.is_ty_var() {
385 return None;
386 }
387 let possible_rcvr_ty = possible_rcvr_ty.fold_with(&mut fudger);
389 let method = self
390 .lookup_method_for_diagnostic(
391 possible_rcvr_ty,
392 segment,
393 DUMMY_SP,
394 call_expr,
395 binding,
396 )
397 .ok()?;
398 if Some(method.def_id)
400 != self.typeck_results.borrow().type_dependent_def_id(call_expr.hir_id)
401 {
402 return None;
403 }
404 let _ = self
408 .at(&ObligationCause::dummy(), self.param_env)
409 .eq(DefineOpaqueTypes::Yes, method.sig.inputs()[idx + 1], arg_ty)
410 .ok()?;
411 self.select_obligations_where_possible(|errs| {
412 errs.clear();
414 });
415 Some(self.resolve_vars_if_possible(possible_rcvr_ty))
416 });
417 if let Some(rcvr_ty) = possible_rcvr_ty {
418 rcvr_ty
419 } else {
420 return false;
421 }
422 }
423 };
424
425 if !self.can_eq(self.param_env, expected_ty, init_ty.fold_with(&mut fudger)) {
428 return false;
429 }
430
431 for window in expr_finder.uses.windows(2) {
432 let [binding, next_usage] = *window else {
436 continue;
437 };
438
439 if binding.hir_id == expr.hir_id {
441 break;
442 }
443
444 let Some(next_use_ty) = self.node_ty_opt(next_usage.hir_id) else {
445 continue;
446 };
447
448 if self.can_eq(self.param_env, expected_ty, next_use_ty.fold_with(&mut fudger)) {
451 continue;
452 }
453
454 if let hir::Node::Expr(parent_expr) = self.tcx.parent_hir_node(binding.hir_id)
455 && let hir::ExprKind::MethodCall(segment, rcvr, args, _) = parent_expr.kind
456 && rcvr.hir_id == binding.hir_id
457 {
458 let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else {
462 continue;
463 };
464 let rcvr_ty = rcvr_ty.fold_with(&mut fudger);
465 let Ok(method) = self.lookup_method_for_diagnostic(
466 rcvr_ty,
467 segment,
468 DUMMY_SP,
469 parent_expr,
470 rcvr,
471 ) else {
472 continue;
473 };
474 if Some(method.def_id)
476 != self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id)
477 {
478 continue;
479 }
480
481 let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger);
482 let ideal_method = self
483 .lookup_method_for_diagnostic(
484 ideal_rcvr_ty,
485 segment,
486 DUMMY_SP,
487 parent_expr,
488 rcvr,
489 )
490 .ok()
491 .and_then(|method| {
492 let _ = self
493 .at(&ObligationCause::dummy(), self.param_env)
494 .eq(DefineOpaqueTypes::Yes, ideal_rcvr_ty, expected_ty)
495 .ok()?;
496 Some(method)
497 });
498
499 for (idx, (expected_arg_ty, arg_expr)) in
502 std::iter::zip(&method.sig.inputs()[1..], args).enumerate()
503 {
504 let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else {
505 continue;
506 };
507 let arg_ty = arg_ty.fold_with(&mut fudger);
508 let _ =
509 self.coerce(arg_expr, arg_ty, *expected_arg_ty, AllowTwoPhase::No, None);
510 self.select_obligations_where_possible(|errs| {
511 errs.clear();
513 });
514 if self.can_eq(self.param_env, rcvr_ty, expected_ty) {
518 continue;
519 }
520 err.span_label(arg_expr.span, format!("this argument has type `{arg_ty}`..."));
521 err.span_label(
522 binding.span,
523 format!("... which causes `{ident}` to have type `{next_use_ty}`"),
524 );
525 if matches!(source, TypeMismatchSource::Ty(_))
534 && let Some(ideal_method) = ideal_method
535 && Some(ideal_method.def_id)
536 == self
537 .typeck_results
538 .borrow()
539 .type_dependent_def_id(parent_expr.hir_id)
540 && let ideal_arg_ty =
541 self.resolve_vars_if_possible(ideal_method.sig.inputs()[idx + 1])
542 && !ideal_arg_ty.has_non_region_infer()
543 {
544 self.emit_type_mismatch_suggestions(
545 err,
546 arg_expr,
547 arg_ty,
548 ideal_arg_ty,
549 None,
550 None,
551 );
552 }
553 return true;
554 }
555 }
556 err.span_label(
557 binding.span,
558 format!("here the type of `{ident}` is inferred to be `{next_use_ty}`"),
559 );
560 return true;
561 }
562
563 false
565 }
566
567 pub(crate) fn annotate_loop_expected_due_to_inference(
570 &self,
571 err: &mut Diag<'_>,
572 expr: &hir::Expr<'_>,
573 error: Option<TypeError<'tcx>>,
574 ) {
575 let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {
576 return;
577 };
578 let mut parent_id = self.tcx.parent_hir_id(expr.hir_id);
579 let mut parent;
580 'outer: loop {
581 let (hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Semi(&ref p), .. })
583 | hir::Node::Block(hir::Block { expr: Some(&ref p), .. })
584 | hir::Node::Expr(&ref p)) = self.tcx.hir_node(parent_id)
585 else {
586 break;
587 };
588 parent = p;
589 parent_id = self.tcx.parent_hir_id(parent_id);
590 let hir::ExprKind::Break(destination, _) = parent.kind else {
591 continue;
592 };
593 let mut parent_id = parent_id;
594 let mut direct = false;
595 loop {
596 let parent = match self.tcx.hir_node(parent_id) {
598 hir::Node::Expr(&ref parent) => {
599 parent_id = self.tcx.parent_hir_id(parent.hir_id);
600 parent
601 }
602 hir::Node::Stmt(hir::Stmt {
603 hir_id,
604 kind: hir::StmtKind::Semi(&ref parent) | hir::StmtKind::Expr(&ref parent),
605 ..
606 }) => {
607 parent_id = self.tcx.parent_hir_id(*hir_id);
608 parent
609 }
610 hir::Node::Block(_) => {
611 parent_id = self.tcx.parent_hir_id(parent_id);
612 parent
613 }
614 _ => break,
615 };
616 if let hir::ExprKind::Loop(..) = parent.kind {
617 direct = !direct;
620 }
621 if let hir::ExprKind::Loop(block, label, _, span) = parent.kind
622 && (destination.label == label || direct)
623 {
624 if let Some((reason_span, message)) =
625 self.maybe_get_coercion_reason(parent_id, parent.span)
626 {
627 err.span_label(reason_span, message);
628 err.span_label(
629 span,
630 format!("this loop is expected to be of type `{expected}`"),
631 );
632 break 'outer;
633 } else {
634 struct FindBreaks<'tcx> {
637 label: Option<rustc_ast::Label>,
638 uses: Vec<&'tcx hir::Expr<'tcx>>,
639 nest_depth: usize,
640 }
641 impl<'tcx> Visitor<'tcx> for FindBreaks<'tcx> {
642 fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
643 let nest_depth = self.nest_depth;
644 if let hir::ExprKind::Loop(_, label, _, _) = ex.kind {
645 if label == self.label {
646 return;
648 }
649 self.nest_depth += 1;
650 }
651 if let hir::ExprKind::Break(destination, _) = ex.kind
652 && (self.label == destination.label
653 || destination.label.is_none() && self.nest_depth == 0)
655 {
656 self.uses.push(ex);
657 }
658 hir::intravisit::walk_expr(self, ex);
659 self.nest_depth = nest_depth;
660 }
661 }
662 let mut expr_finder = FindBreaks { label, uses: vec![], nest_depth: 0 };
663 expr_finder.visit_block(block);
664 let mut exit = false;
665 for ex in expr_finder.uses {
666 let hir::ExprKind::Break(_, val) = ex.kind else {
667 continue;
668 };
669 let ty = match val {
670 Some(val) => {
671 match self.typeck_results.borrow().expr_ty_adjusted_opt(val) {
672 None => continue,
673 Some(ty) => ty,
674 }
675 }
676 None => self.tcx.types.unit,
677 };
678 if self.can_eq(self.param_env, ty, expected) {
679 err.span_label(ex.span, "expected because of this `break`");
680 exit = true;
681 }
682 }
683 if exit {
684 break 'outer;
685 }
686 }
687 }
688 }
689 }
690 }
691
692 fn annotate_expected_due_to_let_ty(
693 &self,
694 err: &mut Diag<'_>,
695 expr: &hir::Expr<'_>,
696 error: Option<TypeError<'tcx>>,
697 ) {
698 match (self.tcx.parent_hir_node(expr.hir_id), error) {
699 (hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), init: Some(init), .. }), _)
700 if init.hir_id == expr.hir_id =>
701 {
702 err.span_label(ty.span, "expected due to this");
704 }
705 (
706 hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }),
707 Some(TypeError::Sorts(ExpectedFound { expected, .. })),
708 ) if rhs.hir_id == expr.hir_id && !expected.is_closure() => {
709 let mut primary_span = lhs.span;
712 let mut secondary_span = lhs.span;
713 let mut post_message = "";
714 match lhs.kind {
715 hir::ExprKind::Path(hir::QPath::Resolved(
716 None,
717 hir::Path {
718 res:
719 hir::def::Res::Def(
720 hir::def::DefKind::Static { .. } | hir::def::DefKind::Const,
721 def_id,
722 ),
723 ..
724 },
725 )) => {
726 if let Some(hir::Node::Item(hir::Item {
727 ident,
728 kind: hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..),
729 ..
730 })) = self.tcx.hir().get_if_local(*def_id)
731 {
732 primary_span = ty.span;
733 secondary_span = ident.span;
734 post_message = " type";
735 }
736 }
737 hir::ExprKind::Path(hir::QPath::Resolved(
738 None,
739 hir::Path { res: hir::def::Res::Local(hir_id), .. },
740 )) => {
741 if let hir::Node::Pat(pat) = self.tcx.hir_node(*hir_id) {
742 primary_span = pat.span;
743 secondary_span = pat.span;
744 match self.tcx.parent_hir_node(pat.hir_id) {
745 hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), .. }) => {
746 primary_span = ty.span;
747 post_message = " type";
748 }
749 hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) => {
750 primary_span = init.span;
751 post_message = " value";
752 }
753 hir::Node::Param(hir::Param { ty_span, .. }) => {
754 primary_span = *ty_span;
755 post_message = " parameter type";
756 }
757 _ => {}
758 }
759 }
760 }
761 _ => {}
762 }
763
764 if primary_span != secondary_span
765 && self
766 .tcx
767 .sess
768 .source_map()
769 .is_multiline(secondary_span.shrink_to_hi().until(primary_span))
770 {
771 err.span_label(secondary_span, "expected due to the type of this binding");
774 err.span_label(primary_span, format!("expected due to this{post_message}"));
775 } else if post_message.is_empty() {
776 err.span_label(primary_span, "expected due to the type of this binding");
778 } else {
779 err.span_label(primary_span, format!("expected due to this{post_message}"));
781 }
782
783 if !lhs.is_syntactic_place_expr() {
784 err.downgrade_to_delayed_bug();
787 }
788 }
789 (
790 hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(_, lhs, rhs), .. }),
791 Some(TypeError::Sorts(ExpectedFound { expected, .. })),
792 ) if rhs.hir_id == expr.hir_id
793 && self.typeck_results.borrow().expr_ty_adjusted_opt(lhs) == Some(expected) =>
794 {
795 err.span_label(lhs.span, format!("expected because this is `{expected}`"));
796 }
797 _ => {}
798 }
799 }
800
801 fn annotate_mut_binding_to_immutable_binding(
820 &self,
821 err: &mut Diag<'_>,
822 expr: &hir::Expr<'_>,
823 error: Option<TypeError<'tcx>>,
824 ) -> bool {
825 if let Some(TypeError::Sorts(ExpectedFound { expected, found })) = error
826 && let ty::Ref(_, inner, hir::Mutability::Not) = expected.kind()
827
828 && self.can_eq(self.param_env, *inner, found)
830
831 && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }) =
833 self.tcx.parent_hir_node(expr.hir_id)
834 && rhs.hir_id == expr.hir_id
835
836 && let hir::ExprKind::Path(hir::QPath::Resolved(
838 None,
839 hir::Path { res: hir::def::Res::Local(hir_id), .. },
840 )) = lhs.kind
841 && let hir::Node::Pat(pat) = self.tcx.hir_node(*hir_id)
842
843 && let hir::Node::Param(hir::Param { ty_span, .. }) =
845 self.tcx.parent_hir_node(pat.hir_id)
846 && let item = self.tcx.hir().get_parent_item(pat.hir_id)
847 && let item = self.tcx.hir_owner_node(item)
848 && let Some(fn_decl) = item.fn_decl()
849
850 && let hir::PatKind::Binding(hir::BindingMode::MUT, _hir_id, ident, _) = pat.kind
852
853 && let Some(ty_ref) = fn_decl
855 .inputs
856 .iter()
857 .filter_map(|ty| match ty.kind {
858 hir::TyKind::Ref(lt, mut_ty) if ty.span == *ty_span => Some((lt, mut_ty)),
859 _ => None,
860 })
861 .next()
862 {
863 let mut sugg = if ty_ref.1.mutbl.is_mut() {
864 vec![]
866 } else {
867 vec![(
869 ty_ref.1.ty.span.shrink_to_lo(),
870 format!(
871 "{}mut ",
872 if ty_ref.0.ident.span.lo() == ty_ref.0.ident.span.hi() { "" } else { " " },
873 ),
874 )]
875 };
876 sugg.extend([
877 (pat.span.until(ident.span), String::new()),
878 (lhs.span.shrink_to_lo(), "*".to_string()),
879 ]);
880 err.multipart_suggestion_verbose(
883 "you might have meant to mutate the pointed at value being passed in, instead of \
884 changing the reference in the local binding",
885 sugg,
886 Applicability::MaybeIncorrect,
887 );
888 return true;
889 }
890 false
891 }
892
893 fn annotate_alternative_method_deref(
894 &self,
895 err: &mut Diag<'_>,
896 expr: &hir::Expr<'_>,
897 error: Option<TypeError<'tcx>>,
898 ) {
899 let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {
900 return;
901 };
902 let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }) =
903 self.tcx.parent_hir_node(expr.hir_id)
904 else {
905 return;
906 };
907 if rhs.hir_id != expr.hir_id || expected.is_closure() {
908 return;
909 }
910 let hir::ExprKind::Unary(hir::UnOp::Deref, deref) = lhs.kind else {
911 return;
912 };
913 let hir::ExprKind::MethodCall(path, base, args, _) = deref.kind else {
914 return;
915 };
916 let Some(self_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(base) else {
917 return;
918 };
919
920 let Ok(pick) = self.lookup_probe_for_diagnostic(
921 path.ident,
922 self_ty,
923 deref,
924 probe::ProbeScope::TraitsInScope,
925 None,
926 ) else {
927 return;
928 };
929
930 let Ok(in_scope_methods) = self.probe_for_name_many(
931 probe::Mode::MethodCall,
932 path.ident,
933 Some(expected),
934 probe::IsSuggestion(true),
935 self_ty,
936 deref.hir_id,
937 probe::ProbeScope::TraitsInScope,
938 ) else {
939 return;
940 };
941
942 let other_methods_in_scope: Vec<_> =
943 in_scope_methods.iter().filter(|c| c.item.def_id != pick.item.def_id).collect();
944
945 let Ok(all_methods) = self.probe_for_name_many(
946 probe::Mode::MethodCall,
947 path.ident,
948 Some(expected),
949 probe::IsSuggestion(true),
950 self_ty,
951 deref.hir_id,
952 probe::ProbeScope::AllTraits,
953 ) else {
954 return;
955 };
956
957 let suggestions: Vec<_> = all_methods
958 .into_iter()
959 .filter(|c| c.item.def_id != pick.item.def_id)
960 .map(|c| {
961 let m = c.item;
962 let generic_args = ty::GenericArgs::for_item(self.tcx, m.def_id, |param, _| {
963 self.var_for_def(deref.span, param)
964 });
965 let mutability =
966 match self.tcx.fn_sig(m.def_id).skip_binder().input(0).skip_binder().kind() {
967 ty::Ref(_, _, hir::Mutability::Mut) => "&mut ",
968 ty::Ref(_, _, _) => "&",
969 _ => "",
970 };
971 vec![
972 (
973 deref.span.until(base.span),
974 format!(
975 "{}({}",
976 with_no_trimmed_paths!(
977 self.tcx.def_path_str_with_args(m.def_id, generic_args,)
978 ),
979 mutability,
980 ),
981 ),
982 match &args {
983 [] => (base.span.shrink_to_hi().with_hi(deref.span.hi()), ")".to_string()),
984 [first, ..] => (base.span.between(first.span), ", ".to_string()),
985 },
986 ]
987 })
988 .collect();
989 if suggestions.is_empty() {
990 return;
991 }
992 let mut path_span: MultiSpan = path.ident.span.into();
993 path_span.push_span_label(
994 path.ident.span,
995 with_no_trimmed_paths!(format!(
996 "refers to `{}`",
997 self.tcx.def_path_str(pick.item.def_id),
998 )),
999 );
1000 let container_id = pick.item.container_id(self.tcx);
1001 let container = with_no_trimmed_paths!(self.tcx.def_path_str(container_id));
1002 for def_id in pick.import_ids {
1003 let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
1004 path_span.push_span_label(
1005 self.tcx.hir().span(hir_id),
1006 format!("`{container}` imported here"),
1007 );
1008 }
1009 let tail = with_no_trimmed_paths!(match &other_methods_in_scope[..] {
1010 [] => return,
1011 [candidate] => format!(
1012 "the method of the same name on {} `{}`",
1013 match candidate.kind {
1014 probe::CandidateKind::InherentImplCandidate { .. } => "the inherent impl for",
1015 _ => "trait",
1016 },
1017 self.tcx.def_path_str(candidate.item.container_id(self.tcx))
1018 ),
1019 _ if other_methods_in_scope.len() < 5 => {
1020 format!(
1021 "the methods of the same name on {}",
1022 listify(
1023 &other_methods_in_scope[..other_methods_in_scope.len() - 1],
1024 |c| format!("`{}`", self.tcx.def_path_str(c.item.container_id(self.tcx)))
1025 )
1026 .unwrap_or_default(),
1027 )
1028 }
1029 _ => format!(
1030 "the methods of the same name on {} other traits",
1031 other_methods_in_scope.len()
1032 ),
1033 });
1034 err.span_note(
1035 path_span,
1036 format!(
1037 "the `{}` call is resolved to the method in `{container}`, shadowing {tail}",
1038 path.ident,
1039 ),
1040 );
1041 if suggestions.len() > other_methods_in_scope.len() {
1042 err.note(format!(
1043 "additionally, there are {} other available methods that aren't in scope",
1044 suggestions.len() - other_methods_in_scope.len()
1045 ));
1046 }
1047 err.multipart_suggestions(
1048 format!(
1049 "you might have meant to call {}; you can use the fully-qualified path to call {} \
1050 explicitly",
1051 if suggestions.len() == 1 {
1052 "the other method"
1053 } else {
1054 "one of the other methods"
1055 },
1056 if suggestions.len() == 1 { "it" } else { "one of them" },
1057 ),
1058 suggestions,
1059 Applicability::MaybeIncorrect,
1060 );
1061 }
1062
1063 pub(crate) fn get_conversion_methods_for_diagnostic(
1064 &self,
1065 span: Span,
1066 expected: Ty<'tcx>,
1067 checked_ty: Ty<'tcx>,
1068 hir_id: hir::HirId,
1069 ) -> Vec<AssocItem> {
1070 let methods = self.probe_for_return_type_for_diagnostic(
1071 span,
1072 probe::Mode::MethodCall,
1073 expected,
1074 checked_ty,
1075 hir_id,
1076 |m| {
1077 self.has_only_self_parameter(m)
1078 && self
1079 .tcx
1080 .has_attr(m.def_id, sym::rustc_conversion_suggestion)
1091 },
1092 );
1093
1094 methods
1095 }
1096
1097 fn has_only_self_parameter(&self, method: &AssocItem) -> bool {
1099 match method.kind {
1100 ty::AssocKind::Fn => {
1101 method.fn_has_self_parameter
1102 && self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len()
1103 == 1
1104 }
1105 _ => false,
1106 }
1107 }
1108
1109 pub(crate) fn maybe_get_block_expr(
1111 &self,
1112 expr: &hir::Expr<'tcx>,
1113 ) -> Option<&'tcx hir::Expr<'tcx>> {
1114 match expr {
1115 hir::Expr { kind: hir::ExprKind::Block(block, ..), .. } => block.expr,
1116 _ => None,
1117 }
1118 }
1119
1120 pub(crate) fn is_destruct_assignment_desugaring(&self, expr: &hir::Expr<'_>) -> bool {
1125 if let hir::ExprKind::Path(hir::QPath::Resolved(
1126 _,
1127 hir::Path { res: hir::def::Res::Local(bind_hir_id), .. },
1128 )) = expr.kind
1129 {
1130 let bind = self.tcx.hir_node(*bind_hir_id);
1131 let parent = self.tcx.parent_hir_node(*bind_hir_id);
1132 if let hir::Node::Pat(hir::Pat {
1133 kind: hir::PatKind::Binding(_, _hir_id, _, _), ..
1134 }) = bind
1135 && let hir::Node::Pat(hir::Pat { default_binding_modes: false, .. }) = parent
1136 {
1137 return true;
1138 }
1139 }
1140 false
1141 }
1142
1143 fn explain_self_literal(
1144 &self,
1145 err: &mut Diag<'_>,
1146 expr: &hir::Expr<'tcx>,
1147 expected: Ty<'tcx>,
1148 found: Ty<'tcx>,
1149 ) {
1150 match expr.peel_drop_temps().kind {
1151 hir::ExprKind::Struct(
1152 hir::QPath::Resolved(
1153 None,
1154 hir::Path { res: hir::def::Res::SelfTyAlias { alias_to, .. }, span, .. },
1155 ),
1156 ..,
1157 )
1158 | hir::ExprKind::Call(
1159 hir::Expr {
1160 kind:
1161 hir::ExprKind::Path(hir::QPath::Resolved(
1162 None,
1163 hir::Path {
1164 res: hir::def::Res::SelfTyAlias { alias_to, .. },
1165 span,
1166 ..
1167 },
1168 )),
1169 ..
1170 },
1171 ..,
1172 ) => {
1173 if let Some(hir::Node::Item(hir::Item {
1174 kind: hir::ItemKind::Impl(hir::Impl { self_ty, .. }),
1175 ..
1176 })) = self.tcx.hir().get_if_local(*alias_to)
1177 {
1178 err.span_label(self_ty.span, "this is the type of the `Self` literal");
1179 }
1180 if let ty::Adt(e_def, e_args) = expected.kind()
1181 && let ty::Adt(f_def, _f_args) = found.kind()
1182 && e_def == f_def
1183 {
1184 err.span_suggestion_verbose(
1185 *span,
1186 "use the type name directly",
1187 self.tcx.value_path_str_with_args(e_def.did(), e_args),
1188 Applicability::MaybeIncorrect,
1189 );
1190 }
1191 }
1192 _ => {}
1193 }
1194 }
1195
1196 fn note_wrong_return_ty_due_to_generic_arg(
1197 &self,
1198 err: &mut Diag<'_>,
1199 expr: &hir::Expr<'_>,
1200 checked_ty: Ty<'tcx>,
1201 ) {
1202 let hir::Node::Expr(parent_expr) = self.tcx.parent_hir_node(expr.hir_id) else {
1203 return;
1204 };
1205 enum CallableKind {
1206 Function,
1207 Method,
1208 Constructor,
1209 }
1210 let mut maybe_emit_help = |def_id: hir::def_id::DefId,
1211 callable: Ident,
1212 args: &[hir::Expr<'_>],
1213 kind: CallableKind| {
1214 let arg_idx = args.iter().position(|a| a.hir_id == expr.hir_id).unwrap();
1215 let fn_ty = self.tcx.type_of(def_id).skip_binder();
1216 if !fn_ty.is_fn() {
1217 return;
1218 }
1219 let fn_sig = fn_ty.fn_sig(self.tcx).skip_binder();
1220 let Some(&arg) = fn_sig
1221 .inputs()
1222 .get(arg_idx + if matches!(kind, CallableKind::Method) { 1 } else { 0 })
1223 else {
1224 return;
1225 };
1226 if matches!(arg.kind(), ty::Param(_))
1227 && fn_sig.output().contains(arg)
1228 && self.node_ty(args[arg_idx].hir_id) == checked_ty
1229 {
1230 let mut multi_span: MultiSpan = parent_expr.span.into();
1231 multi_span.push_span_label(
1232 args[arg_idx].span,
1233 format!(
1234 "this argument influences the {} of `{}`",
1235 if matches!(kind, CallableKind::Constructor) {
1236 "type"
1237 } else {
1238 "return type"
1239 },
1240 callable
1241 ),
1242 );
1243 err.span_help(
1244 multi_span,
1245 format!(
1246 "the {} `{}` due to the type of the argument passed",
1247 match kind {
1248 CallableKind::Function => "return type of this call is",
1249 CallableKind::Method => "return type of this call is",
1250 CallableKind::Constructor => "type constructed contains",
1251 },
1252 checked_ty
1253 ),
1254 );
1255 }
1256 };
1257 match parent_expr.kind {
1258 hir::ExprKind::Call(fun, args) => {
1259 let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else {
1260 return;
1261 };
1262 let hir::def::Res::Def(kind, def_id) = path.res else {
1263 return;
1264 };
1265 let callable_kind = if matches!(kind, hir::def::DefKind::Ctor(_, _)) {
1266 CallableKind::Constructor
1267 } else {
1268 CallableKind::Function
1269 };
1270 maybe_emit_help(def_id, path.segments[0].ident, args, callable_kind);
1271 }
1272 hir::ExprKind::MethodCall(method, _receiver, args, _span) => {
1273 let Some(def_id) =
1274 self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id)
1275 else {
1276 return;
1277 };
1278 maybe_emit_help(def_id, method.ident, args, CallableKind::Method)
1279 }
1280 _ => return,
1281 }
1282 }
1283}
1284
1285pub(crate) enum TypeMismatchSource<'tcx> {
1286 Ty(Ty<'tcx>),
1289 Arg { call_expr: &'tcx hir::Expr<'tcx>, incompatible_arg: usize },
1293}