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