1use rustc_errors::{Applicability, Diag, MultiSpan, listify};
2use rustc_hir::def::Res;
3use rustc_hir::intravisit::Visitor;
4use rustc_hir::{self as hir, find_attr};
5use rustc_infer::infer::DefineOpaqueTypes;
6use rustc_middle::ty::adjustment::AllowTwoPhase;
7use rustc_middle::ty::error::{ExpectedFound, TypeError};
8use rustc_middle::ty::print::with_no_trimmed_paths;
9use rustc_middle::ty::{self, AssocItem, BottomUpFolder, Ty, TypeFoldable, TypeVisitableExt};
10use rustc_span::{DUMMY_SP, Ident, Span, bug, span_bug, sym};
11use rustc_trait_selection::infer::InferCtxtExt;
12use rustc_trait_selection::traits::ObligationCause;
13use tracing::instrument;
14
15use super::method::probe;
16use crate::FnCtxt;
17
18impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19 pub(crate) fn emit_type_mismatch_suggestions(
20 &self,
21 err: &mut Diag<'_>,
22 expr: &hir::Expr<'tcx>,
23 expr_ty: Ty<'tcx>,
24 expected: Ty<'tcx>,
25 expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
26 error: Option<TypeError<'tcx>>,
27 ) {
28 if expr_ty == expected {
29 return;
30 }
31 self.annotate_alternative_method_deref(err, expr, error);
32 self.explain_self_literal(err, expr, expected, expr_ty);
33
34 let suggested = self.suggest_missing_parentheses(err, expr)
36 || self.suggest_missing_unwrap_expect(err, expr, expected, expr_ty)
37 || self.suggest_remove_last_method_call(err, expr, expected)
38 || self.suggest_associated_const(err, expr, expected)
39 || self.suggest_semicolon_in_repeat_expr(err, expr, expr_ty)
40 || self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr)
41 || self.suggest_option_to_bool(err, expr, expr_ty, expected)
42 || self.suggest_collect(err, expr, expected, expr_ty)
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_closure_to_fn_ptr_coercion(err, expr, 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 #[allow(non_exhaustive_omitted_patterns)] match error {
Some(TypeError::RegionsInsufficientlyPolymorphic(..)) => true,
_ => false,
}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 {}
#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("demand_suptype_with_origin",
"rustc_hir_typeck::demand", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_hir_typeck/src/demand.rs"),
::tracing_core::__macro_support::Option::Some(185u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::demand"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("cause")
}> =
::tracing::__macro_support::FieldName::new("cause");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("expected")
}> =
::tracing::__macro_support::FieldName::new("expected");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("actual")
}> =
::tracing::__macro_support::FieldName::new("actual");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&cause)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&expected)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&actual)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: Result<(), Diag<'a>> = loop {};
return __tracing_attr_fake_return;
}
{
self.at(cause,
self.param_env).sup(DefineOpaqueTypes::Yes, expected,
actual).map(|infer_ok|
self.register_infer_ok_obligations(infer_ok)).map_err(|e|
{
self.err_ctxt().report_mismatched_types(cause,
self.param_env, expected, actual, e)
})
}
}
}#[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 {}
#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("demand_coerce_diag",
"rustc_hir_typeck::demand", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_hir_typeck/src/demand.rs"),
::tracing_core::__macro_support::Option::Some(254u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::demand"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("checked_ty")
}> =
::tracing::__macro_support::FieldName::new("checked_ty");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("expected")
}> =
::tracing::__macro_support::FieldName::new("expected");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&checked_ty)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&expected)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: Result<Ty<'tcx>, Diag<'a>> =
loop {};
return __tracing_attr_fake_return;
}
{
let expected =
self.deeply_resolve_ignoring_regions_with_obligations(expected);
let e =
match self.coerce(expr, checked_ty, expected, allow_two_phase,
None) {
Ok(ty) => return Ok(ty),
Err(e) => e,
};
self.adjust_expr_for_assert_eq_macro(&mut expr,
&mut expected_ty_expr);
self.set_tainted_by_errors(self.dcx().span_delayed_bug(expr.span,
"`TypeError` when attempting coercion but no error emitted"));
let expr = expr.peel_drop_temps();
let cause = self.misc(expr.span);
let expr_ty = self.deeply_resolve_ignoring_regions(checked_ty);
let mut err =
self.err_ctxt().report_mismatched_types(&cause,
self.param_env, expected, expr_ty, e);
self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected,
expected_ty_expr, Some(e));
Err(err)
}
}
}#[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 = self.deeply_resolve_ignoring_regions_with_obligations(expected);
264
265 let e = match self.coerce(expr, checked_ty, expected, allow_two_phase, None) {
266 Ok(ty) => return Ok(ty),
267 Err(e) => e,
268 };
269
270 self.adjust_expr_for_assert_eq_macro(&mut expr, &mut expected_ty_expr);
271
272 self.set_tainted_by_errors(self.dcx().span_delayed_bug(
273 expr.span,
274 "`TypeError` when attempting coercion but no error emitted",
275 ));
276 let expr = expr.peel_drop_temps();
277 let cause = self.misc(expr.span);
278 let expr_ty = self.deeply_resolve_ignoring_regions(checked_ty);
279 let mut err =
280 self.err_ctxt().report_mismatched_types(&cause, self.param_env, expected, expr_ty, e);
281
282 self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr, Some(e));
283
284 Err(err)
285 }
286
287 pub(crate) fn note_source_of_type_mismatch_constraint(
290 &self,
291 err: &mut Diag<'_>,
292 expr: &hir::Expr<'_>,
293 source: TypeMismatchSource<'tcx>,
294 ) -> bool {
295 let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind else {
296 return false;
297 };
298 let [hir::PathSegment { ident, args: None, .. }] = p.segments else {
299 return false;
300 };
301 let hir::def::Res::Local(local_hir_id) = p.res else {
302 return false;
303 };
304 let hir::Node::Pat(pat) = self.tcx.hir_node(local_hir_id) else {
305 return false;
306 };
307 let (init_ty_hir_id, init) = match self.tcx.parent_hir_node(pat.hir_id) {
308 hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), init, .. }) => (ty.hir_id, *init),
309 hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) => (init.hir_id, Some(*init)),
310 _ => return false,
311 };
312 let Some(init_ty) = self.node_ty_opt(init_ty_hir_id) else {
313 return false;
314 };
315
316 struct FindExprs<'tcx> {
318 hir_id: hir::HirId,
319 uses: Vec<&'tcx hir::Expr<'tcx>>,
320 }
321 impl<'tcx> Visitor<'tcx> for FindExprs<'tcx> {
322 fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
323 if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = ex.kind
324 && let hir::def::Res::Local(hir_id) = path.res
325 && hir_id == self.hir_id
326 {
327 self.uses.push(ex);
328 }
329 hir::intravisit::walk_expr(self, ex);
330 }
331 }
332
333 let mut expr_finder = FindExprs { hir_id: local_hir_id, uses: init.into_iter().collect() };
334 let body = self.tcx.hir_body_owned_by(self.body_def_id);
335 expr_finder.visit_expr(body.value);
336
337 let mut fudger = BottomUpFolder {
339 tcx: self.tcx,
340 ty_op: |ty| {
341 if let ty::Infer(infer) = ty.kind() {
342 match infer {
343 ty::TyVar(_) => self.next_ty_var(DUMMY_SP),
344 ty::IntVar(_) => self.next_int_var(),
345 ty::FloatVar(_) => self.next_float_var(DUMMY_SP, None),
346 ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
347 bug_impl(None,
format_args!("unexpected fresh ty outside of the trait solver"),
Location::caller())bug!("unexpected fresh ty outside of the trait solver")
348 }
349 }
350 } else {
351 ty
352 }
353 },
354 lt_op: |_| self.tcx.lifetimes.re_erased,
355 ct_op: |ct| {
356 if let ty::ConstKind::Infer(_) = ct.kind() {
357 self.next_const_var(DUMMY_SP)
358 } else {
359 ct
360 }
361 },
362 };
363
364 let expected_ty = match source {
365 TypeMismatchSource::Ty(expected_ty) => expected_ty,
366 TypeMismatchSource::Arg { call_expr, incompatible_arg: idx } => {
373 let hir::ExprKind::MethodCall(segment, _, args, _) = call_expr.kind else {
374 return false;
375 };
376 let Some(arg_ty) = self.node_ty_opt(args[idx].hir_id) else {
377 return false;
378 };
379 let possible_rcvr_ty = expr_finder.uses.iter().rev().find_map(|binding| {
380 let possible_rcvr_ty = self.node_ty_opt(binding.hir_id)?;
381 if possible_rcvr_ty.is_ty_var() {
382 return None;
383 }
384 let possible_rcvr_ty = possible_rcvr_ty.fold_with(&mut fudger);
386 let method = self
387 .lookup_method_for_diagnostic(
388 possible_rcvr_ty,
389 segment,
390 DUMMY_SP,
391 call_expr,
392 binding,
393 )
394 .ok()?;
395 if Some(method.def_id)
397 != self.typeck_results.borrow().type_dependent_def_id(call_expr.hir_id)
398 {
399 return None;
400 }
401 let Some(input_arg) = method.sig.inputs().get(idx + 1) else {
405 if method.sig.splatted().is_some() {
406 return None;
408 } else {
409 bug_impl(Some(self.tcx.def_span(method.def_id)),
format_args!("arg index {0} out of bounds for method with {1} inputs",
idx + 1, method.sig.inputs().len()), Location::caller());span_bug!(
410 self.tcx.def_span(method.def_id),
411 "arg index {} out of bounds for method with {} inputs",
412 idx + 1,
413 method.sig.inputs().len(),
414 );
415 }
416 };
417 let _ = self
418 .at(&ObligationCause::dummy(), self.param_env)
419 .eq(DefineOpaqueTypes::Yes, *input_arg, arg_ty)
420 .ok()?;
421 self.select_obligations_where_possible(|errs| {
422 errs.clear();
424 });
425 Some(self.deeply_resolve_ignoring_regions(possible_rcvr_ty))
426 });
427 let Some(rcvr_ty) = possible_rcvr_ty else { return false };
428 rcvr_ty
429 }
430 };
431
432 if !self.can_eq(self.param_env, expected_ty, init_ty.fold_with(&mut fudger)) {
435 return false;
436 }
437
438 for window in expr_finder.uses.windows(2) {
439 let [binding, next_usage] = *window else {
443 continue;
444 };
445
446 if binding.hir_id == expr.hir_id {
448 break;
449 }
450
451 let Some(next_use_ty) = self.node_ty_opt(next_usage.hir_id) else {
452 continue;
453 };
454
455 if self.can_eq(self.param_env, expected_ty, next_use_ty.fold_with(&mut fudger)) {
458 continue;
459 }
460
461 if let hir::Node::Expr(parent_expr) = self.tcx.parent_hir_node(binding.hir_id)
462 && let hir::ExprKind::MethodCall(segment, rcvr, args, _) = parent_expr.kind
463 && rcvr.hir_id == binding.hir_id
464 {
465 let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else {
469 continue;
470 };
471 let rcvr_ty = rcvr_ty.fold_with(&mut fudger);
472 let Ok(method) = self.lookup_method_for_diagnostic(
473 rcvr_ty,
474 segment,
475 DUMMY_SP,
476 parent_expr,
477 rcvr,
478 ) else {
479 continue;
480 };
481 if Some(method.def_id)
483 != self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id)
484 {
485 continue;
486 }
487
488 let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger);
489 let ideal_method = self
490 .lookup_method_for_diagnostic(
491 ideal_rcvr_ty,
492 segment,
493 DUMMY_SP,
494 parent_expr,
495 rcvr,
496 )
497 .ok()
498 .and_then(|method| {
499 let _ = self
500 .at(&ObligationCause::dummy(), self.param_env)
501 .eq(DefineOpaqueTypes::Yes, ideal_rcvr_ty, expected_ty)
502 .ok()?;
503 Some(method)
504 });
505
506 for (idx, (expected_arg_ty, arg_expr)) in
509 std::iter::zip(&method.sig.inputs()[1..], args).enumerate()
510 {
511 let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else {
512 continue;
513 };
514 let arg_ty = arg_ty.fold_with(&mut fudger);
515 let _ =
516 self.coerce(arg_expr, arg_ty, *expected_arg_ty, AllowTwoPhase::No, None);
517 self.select_obligations_where_possible(|errs| {
518 errs.clear();
520 });
521 if self.can_eq(self.param_env, rcvr_ty, expected_ty) {
525 continue;
526 }
527 err.span_label(arg_expr.span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this argument has type `{0}`...",
arg_ty))
})format!("this argument has type `{arg_ty}`..."));
528 err.span_label(
529 binding.span,
530 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("... which causes `{0}` to have type `{1}`",
ident, next_use_ty))
})format!("... which causes `{ident}` to have type `{next_use_ty}`"),
531 );
532 if #[allow(non_exhaustive_omitted_patterns)] match source {
TypeMismatchSource::Ty(_) => true,
_ => false,
}matches!(source, TypeMismatchSource::Ty(_))
541 && let Some(ideal_method) = ideal_method
542 && Some(ideal_method.def_id)
543 == self
544 .typeck_results
545 .borrow()
546 .type_dependent_def_id(parent_expr.hir_id)
547 && let ideal_arg_ty =
548 self.deeply_resolve_ignoring_regions(ideal_method.sig.inputs()[idx + 1])
549 && !ideal_arg_ty.has_non_region_infer()
550 {
551 self.emit_type_mismatch_suggestions(
552 err,
553 arg_expr,
554 arg_ty,
555 ideal_arg_ty,
556 None,
557 None,
558 );
559 }
560 return true;
561 }
562 }
563 err.span_label(
564 binding.span,
565 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("here the type of `{0}` is inferred to be `{1}`",
ident, next_use_ty))
})format!("here the type of `{ident}` is inferred to be `{next_use_ty}`"),
566 );
567 return true;
568 }
569
570 false
572 }
573
574 pub(crate) fn annotate_loop_expected_due_to_inference(
577 &self,
578 err: &mut Diag<'_>,
579 expr: &hir::Expr<'_>,
580 error: Option<TypeError<'tcx>>,
581 ) {
582 let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {
583 return;
584 };
585 let mut parent_id = self.tcx.parent_hir_id(expr.hir_id);
586 let mut parent;
587 'outer: loop {
588 let (hir::Node::Stmt(&hir::Stmt { kind: hir::StmtKind::Semi(p), .. })
590 | hir::Node::Block(&hir::Block { expr: Some(p), .. })
591 | hir::Node::Expr(p)) = self.tcx.hir_node(parent_id)
592 else {
593 break;
594 };
595 parent = p;
596 parent_id = self.tcx.parent_hir_id(parent_id);
597 let hir::ExprKind::Break(destination, _) = parent.kind else {
598 continue;
599 };
600 let mut parent_id = parent_id;
601 let mut direct = false;
602 loop {
603 let parent = match self.tcx.hir_node(parent_id) {
605 hir::Node::Expr(parent) => {
606 parent_id = self.tcx.parent_hir_id(parent.hir_id);
607 parent
608 }
609 hir::Node::Stmt(hir::Stmt {
610 hir_id,
611 kind: hir::StmtKind::Semi(parent) | hir::StmtKind::Expr(parent),
612 ..
613 }) => {
614 parent_id = self.tcx.parent_hir_id(*hir_id);
615 parent
616 }
617 hir::Node::Stmt(hir::Stmt { hir_id, kind: hir::StmtKind::Let(_), .. }) => {
618 parent_id = self.tcx.parent_hir_id(*hir_id);
619 parent
620 }
621 hir::Node::LetStmt(hir::LetStmt { hir_id, .. }) => {
622 parent_id = self.tcx.parent_hir_id(*hir_id);
623 parent
624 }
625 hir::Node::Block(_) => {
626 parent_id = self.tcx.parent_hir_id(parent_id);
627 parent
628 }
629 _ => break,
630 };
631 if let hir::ExprKind::Loop(..) = parent.kind {
632 direct = !direct;
635 }
636 if let hir::ExprKind::Loop(block, label, _, span) = parent.kind
637 && (destination.label == label || direct)
638 {
639 if let Some((reason_span, message)) =
640 self.maybe_get_coercion_reason(parent_id, parent.span)
641 {
642 err.span_label(reason_span, message);
643 err.span_label(
644 span,
645 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this loop is expected to be of type `{0}`",
expected))
})format!("this loop is expected to be of type `{expected}`"),
646 );
647 break 'outer;
648 } else {
649 struct FindBreaks<'tcx> {
652 label: Option<rustc_ast::Label>,
653 uses: Vec<&'tcx hir::Expr<'tcx>>,
654 nest_depth: usize,
655 }
656 impl<'tcx> Visitor<'tcx> for FindBreaks<'tcx> {
657 fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
658 let nest_depth = self.nest_depth;
659 if let hir::ExprKind::Loop(_, label, _, _) = ex.kind {
660 if label == self.label {
661 return;
663 }
664 self.nest_depth += 1;
665 }
666 if let hir::ExprKind::Break(destination, _) = ex.kind
667 && (self.label == destination.label
668 || destination.label.is_none() && self.nest_depth == 0)
670 {
671 self.uses.push(ex);
672 }
673 hir::intravisit::walk_expr(self, ex);
674 self.nest_depth = nest_depth;
675 }
676 }
677 let mut expr_finder = FindBreaks { label, uses: ::alloc::vec::Vec::new()vec![], nest_depth: 0 };
678 expr_finder.visit_block(block);
679 let mut exit = false;
680 for ex in expr_finder.uses {
681 let hir::ExprKind::Break(_, val) = ex.kind else {
682 continue;
683 };
684 let ty = match val {
685 Some(val) => {
686 match self.typeck_results.borrow().expr_ty_adjusted_opt(val) {
687 None => continue,
688 Some(ty) => ty,
689 }
690 }
691 None => self.tcx.types.unit,
692 };
693 if self.can_eq(self.param_env, ty, expected) {
694 err.span_label(ex.span, "expected because of this `break`");
695 exit = true;
696 }
697 }
698 if exit {
699 break 'outer;
700 }
701 }
702 }
703 }
704 }
705 }
706
707 fn annotate_expected_due_to_let_ty(
708 &self,
709 err: &mut Diag<'_>,
710 expr: &hir::Expr<'_>,
711 error: Option<TypeError<'tcx>>,
712 ) {
713 let mut current_hir_id = expr.hir_id;
715 let parent = self
716 .tcx
717 .hir_parent_iter(expr.hir_id)
718 .find_map(|(parent_hir_id, parent)| match parent {
719 hir::Node::Block(block)
720 if block.expr.is_some_and(|expr| expr.hir_id == current_hir_id) =>
721 {
722 current_hir_id = parent_hir_id;
723 None
724 }
725 hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Block(block, _), .. })
726 if block.hir_id == current_hir_id =>
727 {
728 current_hir_id = parent_hir_id;
729 None
730 }
731 parent => Some(parent),
732 })
733 .expect("an expression must have a non-block ancestor");
734
735 match (parent, error) {
736 (hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), init: Some(init), .. }), _)
737 if init.hir_id == current_hir_id && !ty.span.source_equal(init.span) =>
738 {
739 err.span_label(ty.span, "expected due to this");
741 }
742 (
743 hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }),
744 Some(TypeError::Sorts(ExpectedFound { expected, .. })),
745 ) if rhs.hir_id == expr.hir_id && !expected.is_closure() => {
746 let mut primary_span = lhs.span;
749 let mut secondary_span = lhs.span;
750 let mut post_message = "";
751 match lhs.kind {
752 hir::ExprKind::Path(hir::QPath::Resolved(
753 None,
754 hir::Path {
755 res:
756 hir::def::Res::Def(
757 hir::def::DefKind::Static { .. } | hir::def::DefKind::Const,
758 def_id,
759 ),
760 ..
761 },
762 )) => {
763 if let Some(hir::Node::Item(hir::Item {
764 kind:
765 hir::ItemKind::Static(_, ident, ty, _)
766 | hir::ItemKind::Const(ident, _, ty, _),
767 ..
768 })) = self.tcx.hir_get_if_local(*def_id)
769 {
770 primary_span = ty.span;
771 secondary_span = ident.span;
772 post_message = " type";
773 }
774 }
775 hir::ExprKind::Path(hir::QPath::Resolved(
776 None,
777 hir::Path { res: hir::def::Res::Local(hir_id), .. },
778 )) => {
779 if let hir::Node::Pat(pat) = self.tcx.hir_node(*hir_id) {
780 primary_span = pat.span;
781 secondary_span = pat.span;
782 match self.tcx.parent_hir_node(pat.hir_id) {
783 hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), .. }) => {
784 primary_span = ty.span;
785 post_message = " type";
786 }
787 hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) => {
788 primary_span = init.span;
789 post_message = " value";
790 }
791 hir::Node::Param(hir::Param { ty_span, .. }) => {
792 primary_span = *ty_span;
793 post_message = " parameter type";
794 }
795 _ => {}
796 }
797 }
798 }
799 _ => {}
800 }
801
802 if primary_span != secondary_span
803 && self
804 .tcx
805 .sess
806 .source_map()
807 .is_multiline(secondary_span.shrink_to_hi().until(primary_span))
808 {
809 err.span_label(secondary_span, "expected due to the type of this binding");
812 err.span_label(primary_span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected due to this{0}",
post_message))
})format!("expected due to this{post_message}"));
813 } else if post_message.is_empty() {
814 err.span_label(primary_span, "expected due to the type of this binding");
816 } else {
817 err.span_label(primary_span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected due to this{0}",
post_message))
})format!("expected due to this{post_message}"));
819 }
820
821 if !lhs.is_syntactic_place_expr() {
822 err.downgrade_to_delayed_bug();
825 }
826 }
827 (
828 hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(_, lhs, rhs), .. }),
829 Some(TypeError::Sorts(ExpectedFound { expected, .. })),
830 ) if rhs.hir_id == expr.hir_id
831 && self.typeck_results.borrow().expr_ty_adjusted_opt(lhs) == Some(expected)
832 && !#[allow(non_exhaustive_omitted_patterns)] match lhs.kind {
hir::ExprKind::Let(..) => true,
_ => false,
}matches!(lhs.kind, hir::ExprKind::Let(..)) =>
834 {
835 err.span_label(lhs.span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected because this is `{0}`",
expected))
})format!("expected because this is `{expected}`"));
836 }
837 _ => {}
838 }
839 }
840
841 fn annotate_mut_binding_to_immutable_binding(
860 &self,
861 err: &mut Diag<'_>,
862 expr: &hir::Expr<'_>,
863 expr_ty: Ty<'tcx>,
864 expected: Ty<'tcx>,
865 error: Option<TypeError<'tcx>>,
866 ) -> bool {
867 if let Some(TypeError::Sorts(ExpectedFound { .. })) = error
868 && let ty::Ref(_, inner, hir::Mutability::Not) = expected.kind()
869
870 && self.can_eq(self.param_env, *inner, expr_ty)
872
873 && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }) =
875 self.tcx.parent_hir_node(expr.hir_id)
876 && rhs.hir_id == expr.hir_id
877
878 && let hir::ExprKind::Path(hir::QPath::Resolved(
880 None,
881 hir::Path { res: hir::def::Res::Local(hir_id), .. },
882 )) = lhs.kind
883 && let hir::Node::Pat(pat) = self.tcx.hir_node(*hir_id)
884
885 && let hir::Node::Param(hir::Param { ty_span, .. }) =
887 self.tcx.parent_hir_node(pat.hir_id)
888 && let item = self.tcx.hir_get_parent_item(pat.hir_id)
889 && let item = self.tcx.hir_owner_node(item)
890 && let Some(fn_decl) = item.fn_decl()
891
892 && let hir::PatKind::Binding(hir::BindingMode::MUT, _hir_id, ident, _) = pat.kind
894
895 && let Some(ty_ref) = fn_decl
897 .inputs
898 .iter()
899 .filter_map(|ty| match ty.kind {
900 hir::TyKind::Ref(lt, mut_ty) if ty.span == *ty_span => Some((lt, mut_ty)),
901 _ => None,
902 })
903 .next()
904 {
905 let mut sugg = if ty_ref.1.mutbl.is_mut() {
906 ::alloc::vec::Vec::new()vec![]
908 } else {
909 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(ty_ref.1.ty.span.shrink_to_lo(),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}mut ",
if ty_ref.0.ident.span.is_empty() { "" } else { " " }))
}))]))vec![(
911 ty_ref.1.ty.span.shrink_to_lo(),
912 format!("{}mut ", if ty_ref.0.ident.span.is_empty() { "" } else { " " },),
913 )]
914 };
915 sugg.extend([
916 (pat.span.until(ident.span), String::new()),
917 (lhs.span.shrink_to_lo(), "*".to_string()),
918 ]);
919 err.multipart_suggestion(
922 "you might have meant to mutate the pointed at value being passed in, instead of \
923 changing the reference in the local binding",
924 sugg,
925 Applicability::MaybeIncorrect,
926 );
927 return true;
928 }
929 false
930 }
931
932 fn annotate_alternative_method_deref(
933 &self,
934 err: &mut Diag<'_>,
935 expr: &hir::Expr<'_>,
936 error: Option<TypeError<'tcx>>,
937 ) {
938 let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {
939 return;
940 };
941 let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }) =
942 self.tcx.parent_hir_node(expr.hir_id)
943 else {
944 return;
945 };
946 if rhs.hir_id != expr.hir_id || expected.is_closure() {
947 return;
948 }
949 let hir::ExprKind::Unary(hir::UnOp::Deref, deref) = lhs.kind else {
950 return;
951 };
952 let hir::ExprKind::MethodCall(path, base, args, _) = deref.kind else {
953 return;
954 };
955 let Some(self_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(base) else {
956 return;
957 };
958
959 let Ok(pick) = self.lookup_probe_for_diagnostic(
960 path.ident,
961 self_ty,
962 deref,
963 probe::ProbeScope::TraitsInScope,
964 None,
965 ) else {
966 return;
967 };
968
969 let Ok(in_scope_methods) = self.probe_for_name_many(
970 probe::Mode::MethodCall,
971 path.ident,
972 Some(expected),
973 probe::IsSuggestion(true),
974 self_ty,
975 deref.hir_id,
976 probe::ProbeScope::TraitsInScope,
977 ) else {
978 return;
979 };
980
981 let other_methods_in_scope: Vec<_> =
982 in_scope_methods.iter().filter(|c| c.item.def_id != pick.item.def_id).collect();
983
984 let Ok(all_methods) = self.probe_for_name_many(
985 probe::Mode::MethodCall,
986 path.ident,
987 Some(expected),
988 probe::IsSuggestion(true),
989 self_ty,
990 deref.hir_id,
991 probe::ProbeScope::AllTraits,
992 ) else {
993 return;
994 };
995
996 let suggestions: Vec<_> = all_methods
997 .into_iter()
998 .filter(|c| c.item.def_id != pick.item.def_id)
999 .map(|c| {
1000 let m = c.item;
1001 let generic_args = ty::GenericArgs::for_item(self.tcx, m.def_id, |param, _| {
1002 self.var_for_def(deref.span, param)
1003 });
1004 let mutability =
1005 match self.tcx.fn_sig(m.def_id).skip_binder().input(0).skip_binder().kind() {
1006 ty::Ref(_, _, hir::Mutability::Mut) => "&mut ",
1007 ty::Ref(_, _, _) => "&",
1008 _ => "",
1009 };
1010 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(deref.span.until(base.span),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}({1}",
{
let _guard = NoTrimmedGuard::new();
self.tcx.def_path_str_with_args(m.def_id, generic_args)
}, mutability))
})),
match &args {
[] =>
(base.span.shrink_to_hi().with_hi(deref.span.hi()),
")".to_string()),
[first, ..] =>
(base.span.between(first.span), ", ".to_string()),
}]))vec![
1011 (
1012 deref.span.until(base.span),
1013 format!(
1014 "{}({}",
1015 with_no_trimmed_paths!(
1016 self.tcx.def_path_str_with_args(m.def_id, generic_args,)
1017 ),
1018 mutability,
1019 ),
1020 ),
1021 match &args {
1022 [] => (base.span.shrink_to_hi().with_hi(deref.span.hi()), ")".to_string()),
1023 [first, ..] => (base.span.between(first.span), ", ".to_string()),
1024 },
1025 ]
1026 })
1027 .collect();
1028 if suggestions.is_empty() {
1029 return;
1030 }
1031 let mut path_span: MultiSpan = path.ident.span.into();
1032 path_span.push_span_label(
1033 path.ident.span,
1034 {
let _guard = NoTrimmedGuard::new();
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("refers to `{0}`",
self.tcx.def_path_str(pick.item.def_id)))
})
}with_no_trimmed_paths!(format!(
1035 "refers to `{}`",
1036 self.tcx.def_path_str(pick.item.def_id),
1037 )),
1038 );
1039 let container_id = pick.item.container_id(self.tcx);
1040 let container = { let _guard = NoTrimmedGuard::new(); self.tcx.def_path_str(container_id) }with_no_trimmed_paths!(self.tcx.def_path_str(container_id));
1041 for &def_id in pick.import_ids {
1042 let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
1043 path_span
1044 .push_span_label(self.tcx.hir_span(hir_id), ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` imported here", container))
})format!("`{container}` imported here"));
1045 }
1046 let tail = {
let _guard = NoTrimmedGuard::new();
match &other_methods_in_scope[..] {
[] => return,
[candidate] =>
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the method of the same name on {0} `{1}`",
match candidate.kind {
probe::CandidateKind::InherentImplCandidate { .. } =>
"the inherent impl for",
_ => "trait",
},
self.tcx.def_path_str(candidate.item.container_id(self.tcx))))
}),
_ if other_methods_in_scope.len() < 5 => {
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the methods of the same name on {0}",
listify(&other_methods_in_scope[..other_methods_in_scope.len()
- 1],
|c|
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`",
self.tcx.def_path_str(c.item.container_id(self.tcx))))
})).unwrap_or_default()))
})
}
_ =>
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the methods of the same name on {0} other traits",
other_methods_in_scope.len()))
}),
}
}with_no_trimmed_paths!(match &other_methods_in_scope[..] {
1047 [] => return,
1048 [candidate] => format!(
1049 "the method of the same name on {} `{}`",
1050 match candidate.kind {
1051 probe::CandidateKind::InherentImplCandidate { .. } => "the inherent impl for",
1052 _ => "trait",
1053 },
1054 self.tcx.def_path_str(candidate.item.container_id(self.tcx))
1055 ),
1056 _ if other_methods_in_scope.len() < 5 => {
1057 format!(
1058 "the methods of the same name on {}",
1059 listify(
1060 &other_methods_in_scope[..other_methods_in_scope.len() - 1],
1061 |c| format!("`{}`", self.tcx.def_path_str(c.item.container_id(self.tcx)))
1062 )
1063 .unwrap_or_default(),
1064 )
1065 }
1066 _ => format!(
1067 "the methods of the same name on {} other traits",
1068 other_methods_in_scope.len()
1069 ),
1070 });
1071 err.span_note(
1072 path_span,
1073 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the `{0}` call is resolved to the method in `{1}`, shadowing {2}",
path.ident, container, tail))
})format!(
1074 "the `{}` call is resolved to the method in `{container}`, shadowing {tail}",
1075 path.ident,
1076 ),
1077 );
1078 if suggestions.len() > other_methods_in_scope.len() {
1079 err.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("additionally, there are {0} other available methods that aren\'t in scope",
suggestions.len() - other_methods_in_scope.len()))
})format!(
1080 "additionally, there are {} other available methods that aren't in scope",
1081 suggestions.len() - other_methods_in_scope.len()
1082 ));
1083 }
1084 err.multipart_suggestions(
1085 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("you might have meant to call {0}; you can use the fully-qualified path to call {1} explicitly",
if suggestions.len() == 1 {
"the other method"
} else { "one of the other methods" },
if suggestions.len() == 1 { "it" } else { "one of them" }))
})format!(
1086 "you might have meant to call {}; you can use the fully-qualified path to call {} \
1087 explicitly",
1088 if suggestions.len() == 1 {
1089 "the other method"
1090 } else {
1091 "one of the other methods"
1092 },
1093 if suggestions.len() == 1 { "it" } else { "one of them" },
1094 ),
1095 suggestions,
1096 Applicability::MaybeIncorrect,
1097 );
1098 }
1099
1100 pub(crate) fn get_conversion_methods_for_diagnostic(
1101 &self,
1102 span: Span,
1103 expected: Ty<'tcx>,
1104 checked_ty: Ty<'tcx>,
1105 hir_id: hir::HirId,
1106 ) -> Vec<AssocItem> {
1107 let methods = self.probe_for_return_type_for_diagnostic(
1108 span,
1109 probe::Mode::MethodCall,
1110 expected,
1111 checked_ty,
1112 hir_id,
1113 |m| {
1114 self.has_only_self_parameter(m)
1115 && {
{
'done:
{
for i in
::rustc_attr_ir::HasAttrs::get_attrs(m.def_id, &self.tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(RustcConversionSuggestion)
=> {
break 'done Some(());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}.is_some()find_attr!(self.tcx, m.def_id, RustcConversionSuggestion)
1126 },
1127 );
1128
1129 methods
1130 }
1131
1132 fn has_only_self_parameter(&self, method: &AssocItem) -> bool {
1134 method.is_method()
1135 && self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len() == 1
1136 }
1137
1138 pub(crate) fn maybe_get_block_expr(
1140 &self,
1141 expr: &hir::Expr<'tcx>,
1142 ) -> Option<&'tcx hir::Expr<'tcx>> {
1143 match expr {
1144 hir::Expr { kind: hir::ExprKind::Block(block, ..), .. } => block.expr,
1145 _ => None,
1146 }
1147 }
1148
1149 pub(crate) fn is_destruct_assignment_desugaring(&self, expr: &hir::Expr<'_>) -> bool {
1154 if let hir::ExprKind::Path(hir::QPath::Resolved(
1155 _,
1156 hir::Path { res: hir::def::Res::Local(bind_hir_id), .. },
1157 )) = expr.kind
1158 && let bind = self.tcx.hir_node(*bind_hir_id)
1159 && let parent = self.tcx.parent_hir_node(*bind_hir_id)
1160 && let hir::Node::Pat(hir::Pat {
1161 kind: hir::PatKind::Binding(_, _hir_id, _, _), ..
1162 }) = bind
1163 && let hir::Node::Pat(hir::Pat { default_binding_modes: false, .. }) = parent
1164 {
1165 true
1166 } else {
1167 false
1168 }
1169 }
1170
1171 fn explain_self_literal(
1172 &self,
1173 err: &mut Diag<'_>,
1174 expr: &hir::Expr<'tcx>,
1175 expected: Ty<'tcx>,
1176 found: Ty<'tcx>,
1177 ) {
1178 match expr.peel_drop_temps().kind {
1179 hir::ExprKind::Struct(
1180 hir::QPath::Resolved(
1181 None,
1182 hir::Path { res: hir::def::Res::SelfTyAlias { alias_to, .. }, span, .. },
1183 ),
1184 ..,
1185 )
1186 | hir::ExprKind::Call(
1187 hir::Expr {
1188 kind:
1189 hir::ExprKind::Path(hir::QPath::Resolved(
1190 None,
1191 hir::Path {
1192 res: hir::def::Res::SelfTyAlias { alias_to, .. },
1193 span,
1194 ..
1195 },
1196 )),
1197 ..
1198 },
1199 ..,
1200 ) => {
1201 if let Some(hir::Node::Item(hir::Item {
1202 kind: hir::ItemKind::Impl(hir::Impl { self_ty, .. }),
1203 ..
1204 })) = self.tcx.hir_get_if_local(*alias_to)
1205 {
1206 err.span_label(self_ty.span, "this is the type of the `Self` literal");
1207 }
1208 if let ty::Adt(e_def, e_args) = expected.kind()
1209 && let ty::Adt(f_def, _f_args) = found.kind()
1210 && e_def == f_def
1211 {
1212 err.span_suggestion_verbose(
1213 *span,
1214 "use the type name directly",
1215 self.tcx.value_path_str_with_args(e_def.did(), e_args),
1216 Applicability::MaybeIncorrect,
1217 );
1218 }
1219 }
1220 _ => {}
1221 }
1222 }
1223
1224 fn note_wrong_return_ty_due_to_generic_arg(
1225 &self,
1226 err: &mut Diag<'_>,
1227 expr: &hir::Expr<'_>,
1228 checked_ty: Ty<'tcx>,
1229 ) {
1230 let hir::Node::Expr(parent_expr) = self.tcx.parent_hir_node(expr.hir_id) else {
1231 return;
1232 };
1233 if parent_expr.span.desugaring_kind().is_some() {
1234 return;
1235 }
1236 enum CallableKind {
1237 Function,
1238 Method,
1239 Constructor,
1240 }
1241 let mut maybe_emit_help = |def_id: hir::def_id::DefId,
1242 callable: Ident,
1243 args: &[hir::Expr<'_>],
1244 kind: CallableKind| {
1245 let arg_idx = args.iter().position(|a| a.hir_id == expr.hir_id).unwrap();
1246 let fn_ty = self.tcx.type_of(def_id).skip_binder();
1247 if !fn_ty.is_fn() {
1248 return;
1249 }
1250 let fn_sig = fn_ty.fn_sig(self.tcx).skip_binder();
1251 let Some(&arg) = fn_sig
1252 .inputs()
1253 .get(arg_idx + if #[allow(non_exhaustive_omitted_patterns)] match kind {
CallableKind::Method => true,
_ => false,
}matches!(kind, CallableKind::Method) { 1 } else { 0 })
1254 else {
1255 return;
1256 };
1257 if #[allow(non_exhaustive_omitted_patterns)] match arg.kind() {
ty::Param(_) => true,
_ => false,
}matches!(arg.kind(), ty::Param(_))
1258 && fn_sig.output().contains(arg)
1259 && self.node_ty(args[arg_idx].hir_id) == checked_ty
1260 {
1261 let mut multi_span: MultiSpan = parent_expr.span.into();
1262 multi_span.push_span_label(
1263 args[arg_idx].span,
1264 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this argument influences the {0} of `{1}`",
if #[allow(non_exhaustive_omitted_patterns)] match kind {
CallableKind::Constructor => true,
_ => false,
} {
"type"
} else { "return type" }, callable))
})format!(
1265 "this argument influences the {} of `{}`",
1266 if matches!(kind, CallableKind::Constructor) {
1267 "type"
1268 } else {
1269 "return type"
1270 },
1271 callable
1272 ),
1273 );
1274 err.span_help(
1275 multi_span,
1276 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the {0} `{1}` due to the type of the argument passed",
match kind {
CallableKind::Function => "return type of this call is",
CallableKind::Method => "return type of this call is",
CallableKind::Constructor => "type constructed contains",
}, checked_ty))
})format!(
1277 "the {} `{}` due to the type of the argument passed",
1278 match kind {
1279 CallableKind::Function => "return type of this call is",
1280 CallableKind::Method => "return type of this call is",
1281 CallableKind::Constructor => "type constructed contains",
1282 },
1283 checked_ty
1284 ),
1285 );
1286 }
1287 };
1288 match parent_expr.kind {
1289 hir::ExprKind::Call(fun, args) => {
1290 let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else {
1291 return;
1292 };
1293 let hir::def::Res::Def(kind, def_id) = path.res else {
1294 return;
1295 };
1296 let callable_kind = if #[allow(non_exhaustive_omitted_patterns)] match kind {
hir::def::DefKind::Ctor(_, _) => true,
_ => false,
}matches!(kind, hir::def::DefKind::Ctor(_, _)) {
1297 CallableKind::Constructor
1298 } else {
1299 CallableKind::Function
1300 };
1301 maybe_emit_help(def_id, path.segments.last().unwrap().ident, args, callable_kind);
1302 }
1303 hir::ExprKind::MethodCall(method, _receiver, args, _span) => {
1304 let Some(def_id) =
1305 self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id)
1306 else {
1307 return;
1308 };
1309 maybe_emit_help(def_id, method.ident, args, CallableKind::Method)
1310 }
1311 _ => return,
1312 }
1313 }
1314}
1315
1316pub(crate) enum TypeMismatchSource<'tcx> {
1317 Ty(Ty<'tcx>),
1320 Arg { call_expr: &'tcx hir::Expr<'tcx>, incompatible_arg: usize },
1324}