1use rustc_attr_ir::find_attr;
2use rustc_errors::{Applicability, Diag, MultiSpan, listify, pluralize};
3use rustc_hir as hir;
4use rustc_hir::def::{DefKind, Res};
5use rustc_hir::intravisit::Visitor;
6use rustc_infer::infer::DefineOpaqueTypes;
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, bug, span_bug, 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_for_unop(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_collect(err, expr, expected, expr_ty)
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_closure_to_fn_ptr_coercion(err, expr, 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, expr_ty, expected, error) {
89 return;
90 }
91
92 if #[allow(non_exhaustive_omitted_patterns)] match error {
Some(TypeError::RegionsInsufficientlyPolymorphic(..)) => true,
_ => false,
}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 {}
#[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/28221559263a3976766cf305940e80e30cf9ba8a/compiler/rustc_hir_typeck/src/demand.rs"),
::tracing_core::__macro_support::Option::Some(186u32),
::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")]
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 {}
#[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/28221559263a3976766cf305940e80e30cf9ba8a/compiler/rustc_hir_typeck/src/demand.rs"),
::tracing_core::__macro_support::Option::Some(255u32),
::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))]
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.deeply_resolve_ignoring_regions_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.deeply_resolve_ignoring_regions(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::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind else {
297 return false;
298 };
299 let [hir::PathSegment { ident, args: None, .. }] = p.segments else {
300 return false;
301 };
302 let hir::def::Res::Local(local_hir_id) = p.res else {
303 return false;
304 };
305 let hir::Node::Pat(pat) = self.tcx.hir_node(local_hir_id) else {
306 return false;
307 };
308 let (init_ty_hir_id, init) = match self.tcx.parent_hir_node(pat.hir_id) {
309 hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), init, .. }) => (ty.hir_id, *init),
310 hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) => (init.hir_id, Some(*init)),
311 _ => return false,
312 };
313 let Some(init_ty) = self.node_ty_opt(init_ty_hir_id) else {
314 return false;
315 };
316
317 struct FindExprs<'tcx> {
319 hir_id: hir::HirId,
320 uses: Vec<&'tcx hir::Expr<'tcx>>,
321 }
322 impl<'tcx> Visitor<'tcx> for FindExprs<'tcx> {
323 fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
324 if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = ex.kind
325 && let hir::def::Res::Local(hir_id) = path.res
326 && hir_id == self.hir_id
327 {
328 self.uses.push(ex);
329 }
330 hir::intravisit::walk_expr(self, ex);
331 }
332 }
333
334 let mut expr_finder = FindExprs { hir_id: local_hir_id, uses: init.into_iter().collect() };
335 let body = self.tcx.hir_body_owned_by(self.body_def_id);
336 expr_finder.visit_expr(body.value);
337
338 let mut fudger = BottomUpFolder {
340 tcx: self.tcx,
341 ty_op: |ty| {
342 if let ty::Infer(infer) = ty.kind() {
343 match infer {
344 ty::TyVar(_) => self.next_ty_var(DUMMY_SP),
345 ty::IntVar(_) => self.next_int_var(),
346 ty::FloatVar(_) => self.next_float_var(DUMMY_SP, None),
347 ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
348 ::rustc_span::macros::bug_impl(None,
format_args!("unexpected fresh ty outside of the trait solver"),
Location::caller())bug!("unexpected fresh ty outside of the trait solver")
349 }
350 }
351 } else {
352 ty
353 }
354 },
355 lt_op: |_| self.tcx.lifetimes.re_erased,
356 ct_op: |ct| {
357 if let ty::ConstKind::Infer(_) = ct.kind() {
358 self.next_const_var(DUMMY_SP)
359 } else {
360 ct
361 }
362 },
363 };
364
365 let expected_ty = match source {
366 TypeMismatchSource::Ty(expected_ty) => expected_ty,
367 TypeMismatchSource::Arg { call_expr, incompatible_arg: idx } => {
374 let hir::ExprKind::MethodCall(segment, _, args, _) = call_expr.kind else {
375 return false;
376 };
377 let Some(arg_ty) = self.node_ty_opt(args[idx].hir_id) else {
378 return false;
379 };
380 let possible_rcvr_ty = expr_finder.uses.iter().rev().find_map(|binding| {
381 let possible_rcvr_ty = self.node_ty_opt(binding.hir_id)?;
382 if possible_rcvr_ty.is_ty_var() {
383 return None;
384 }
385 let possible_rcvr_ty = possible_rcvr_ty.fold_with(&mut fudger);
387 let method = self
388 .lookup_method_for_diagnostic(
389 possible_rcvr_ty,
390 segment,
391 DUMMY_SP,
392 call_expr,
393 binding,
394 )
395 .ok()?;
396 if Some(method.def_id)
398 != self.typeck_results.borrow().type_dependent_def_id(call_expr.hir_id)
399 {
400 return None;
401 }
402 let Some(input_arg) = method.sig.inputs().get(idx + 1) else {
406 if method.sig.splatted().is_some() {
407 return None;
409 } else {
410 ::rustc_span::macros::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!(
411 self.tcx.def_span(method.def_id),
412 "arg index {} out of bounds for method with {} inputs",
413 idx + 1,
414 method.sig.inputs().len(),
415 );
416 }
417 };
418 let _ = self
419 .at(&ObligationCause::dummy(), self.param_env)
420 .eq(DefineOpaqueTypes::Yes, *input_arg, arg_ty)
421 .ok()?;
422 self.select_obligations_where_possible(|errs| {
423 errs.clear();
425 });
426 Some(self.deeply_resolve_ignoring_regions(possible_rcvr_ty))
427 });
428 let Some(rcvr_ty) = possible_rcvr_ty else { return false };
429 rcvr_ty
430 }
431 };
432
433 if !self.can_eq(self.param_env, expected_ty, init_ty.fold_with(&mut fudger)) {
436 return false;
437 }
438
439 for window in expr_finder.uses.windows(2) {
440 let [binding, next_usage] = *window else {
444 continue;
445 };
446
447 if binding.hir_id == expr.hir_id {
449 break;
450 }
451
452 let Some(next_use_ty) = self.node_ty_opt(next_usage.hir_id) else {
453 continue;
454 };
455
456 if self.can_eq(self.param_env, expected_ty, next_use_ty.fold_with(&mut fudger)) {
459 continue;
460 }
461
462 if let hir::Node::Expr(parent_expr) = self.tcx.parent_hir_node(binding.hir_id)
463 && let hir::ExprKind::MethodCall(segment, rcvr, args, _) = parent_expr.kind
464 && rcvr.hir_id == binding.hir_id
465 {
466 let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else {
470 continue;
471 };
472 let rcvr_ty = rcvr_ty.fold_with(&mut fudger);
473 let Ok(method) = self.lookup_method_for_diagnostic(
474 rcvr_ty,
475 segment,
476 DUMMY_SP,
477 parent_expr,
478 rcvr,
479 ) else {
480 continue;
481 };
482 if Some(method.def_id)
484 != self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id)
485 {
486 continue;
487 }
488
489 let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger);
490 let ideal_method = self
491 .lookup_method_for_diagnostic(
492 ideal_rcvr_ty,
493 segment,
494 DUMMY_SP,
495 parent_expr,
496 rcvr,
497 )
498 .ok()
499 .and_then(|method| {
500 let _ = self
501 .at(&ObligationCause::dummy(), self.param_env)
502 .eq(DefineOpaqueTypes::Yes, ideal_rcvr_ty, expected_ty)
503 .ok()?;
504 Some(method)
505 });
506
507 for (idx, (expected_arg_ty, arg_expr)) in
510 std::iter::zip(&method.sig.inputs()[1..], args).enumerate()
511 {
512 let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else {
513 continue;
514 };
515 let arg_ty = arg_ty.fold_with(&mut fudger);
516 let _ =
517 self.coerce(arg_expr, arg_ty, *expected_arg_ty, AllowTwoPhase::No, None);
518 self.select_obligations_where_possible(|errs| {
519 errs.clear();
521 });
522 if self.can_eq(self.param_env, rcvr_ty, expected_ty) {
526 continue;
527 }
528 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}`..."));
529 err.span_label(
530 binding.span,
531 ::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}`"),
532 );
533 if #[allow(non_exhaustive_omitted_patterns)] match source {
TypeMismatchSource::Ty(_) => true,
_ => false,
}matches!(source, TypeMismatchSource::Ty(_))
542 && let Some(ideal_method) = ideal_method
543 && Some(ideal_method.def_id)
544 == self
545 .typeck_results
546 .borrow()
547 .type_dependent_def_id(parent_expr.hir_id)
548 && let ideal_arg_ty =
549 self.deeply_resolve_ignoring_regions(ideal_method.sig.inputs()[idx + 1])
550 && !ideal_arg_ty.has_non_region_infer()
551 {
552 self.emit_type_mismatch_suggestions(
553 err,
554 arg_expr,
555 arg_ty,
556 ideal_arg_ty,
557 None,
558 None,
559 );
560 }
561 return true;
562 }
563 }
564 err.span_label(
565 binding.span,
566 ::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}`"),
567 );
568 return true;
569 }
570
571 false
573 }
574
575 pub(crate) fn annotate_loop_expected_due_to_inference(
578 &self,
579 err: &mut Diag<'_>,
580 expr: &hir::Expr<'_>,
581 error: Option<TypeError<'tcx>>,
582 ) {
583 let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {
584 return;
585 };
586 let mut parent_id = self.tcx.parent_hir_id(expr.hir_id);
587 let mut parent;
588 'outer: loop {
589 let (hir::Node::Stmt(&hir::Stmt { kind: hir::StmtKind::Semi(p), .. })
591 | hir::Node::Block(&hir::Block { expr: Some(p), .. })
592 | hir::Node::Expr(p)) = self.tcx.hir_node(parent_id)
593 else {
594 break;
595 };
596 parent = p;
597 parent_id = self.tcx.parent_hir_id(parent_id);
598 let hir::ExprKind::Break(destination, _) = parent.kind else {
599 continue;
600 };
601 let mut parent_id = parent_id;
602 let mut direct = false;
603 loop {
604 let parent = match self.tcx.hir_node(parent_id) {
606 hir::Node::Expr(parent) => {
607 parent_id = self.tcx.parent_hir_id(parent.hir_id);
608 parent
609 }
610 hir::Node::Stmt(hir::Stmt {
611 hir_id,
612 kind: hir::StmtKind::Semi(parent) | hir::StmtKind::Expr(parent),
613 ..
614 }) => {
615 parent_id = self.tcx.parent_hir_id(*hir_id);
616 parent
617 }
618 hir::Node::Stmt(hir::Stmt { hir_id, kind: hir::StmtKind::Let(_), .. }) => {
619 parent_id = self.tcx.parent_hir_id(*hir_id);
620 parent
621 }
622 hir::Node::LetStmt(hir::LetStmt { hir_id, .. }) => {
623 parent_id = self.tcx.parent_hir_id(*hir_id);
624 parent
625 }
626 hir::Node::Block(_) => {
627 parent_id = self.tcx.parent_hir_id(parent_id);
628 parent
629 }
630 _ => break,
631 };
632 if let hir::ExprKind::Loop(..) = parent.kind {
633 direct = !direct;
636 }
637 if let hir::ExprKind::Loop(block, label, _, span) = parent.kind
638 && (destination.label == label || direct)
639 {
640 if let Some((reason_span, message)) =
641 self.maybe_get_coercion_reason(parent_id, parent.span)
642 {
643 err.span_label(reason_span, message);
644 err.span_label(
645 span,
646 ::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}`"),
647 );
648 break 'outer;
649 } else {
650 struct FindBreaks<'tcx> {
653 label: Option<rustc_ast::Label>,
654 uses: Vec<&'tcx hir::Expr<'tcx>>,
655 nest_depth: usize,
656 }
657 impl<'tcx> Visitor<'tcx> for FindBreaks<'tcx> {
658 fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
659 let nest_depth = self.nest_depth;
660 if let hir::ExprKind::Loop(_, label, _, _) = ex.kind {
661 if label == self.label {
662 return;
664 }
665 self.nest_depth += 1;
666 }
667 if let hir::ExprKind::Break(destination, _) = ex.kind
668 && (self.label == destination.label
669 || destination.label.is_none() && self.nest_depth == 0)
671 {
672 self.uses.push(ex);
673 }
674 hir::intravisit::walk_expr(self, ex);
675 self.nest_depth = nest_depth;
676 }
677 }
678 let mut expr_finder = FindBreaks { label, uses: ::alloc::vec::Vec::new()vec![], nest_depth: 0 };
679 expr_finder.visit_block(block);
680 let mut exit = false;
681 for ex in expr_finder.uses {
682 let hir::ExprKind::Break(_, val) = ex.kind else {
683 continue;
684 };
685 let ty = match val {
686 Some(val) => {
687 match self.typeck_results.borrow().expr_ty_adjusted_opt(val) {
688 None => continue,
689 Some(ty) => ty,
690 }
691 }
692 None => self.tcx.types.unit,
693 };
694 if self.can_eq(self.param_env, ty, expected) {
695 err.span_label(ex.span, "expected because of this `break`");
696 exit = true;
697 }
698 }
699 if exit {
700 break 'outer;
701 }
702 }
703 }
704 }
705 }
706 }
707
708 fn annotate_expected_due_to_let_ty(
709 &self,
710 err: &mut Diag<'_>,
711 expr: &hir::Expr<'_>,
712 error: Option<TypeError<'tcx>>,
713 ) {
714 let mut current_hir_id = expr.hir_id;
716 let parent = self
717 .tcx
718 .hir_parent_iter(expr.hir_id)
719 .find_map(|(parent_hir_id, parent)| match parent {
720 hir::Node::Block(block)
721 if block.expr.is_some_and(|expr| expr.hir_id == current_hir_id) =>
722 {
723 current_hir_id = parent_hir_id;
724 None
725 }
726 hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Block(block, _), .. })
727 if block.hir_id == current_hir_id =>
728 {
729 current_hir_id = parent_hir_id;
730 None
731 }
732 parent => Some(parent),
733 })
734 .expect("an expression must have a non-block ancestor");
735
736 match (parent, error) {
737 (hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), init: Some(init), .. }), _)
738 if init.hir_id == current_hir_id && ty.span.lo_hi() != init.span.lo_hi() =>
739 {
740 err.span_label(ty.span, "expected due to this");
742 }
743 (
744 hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }),
745 Some(TypeError::Sorts(ExpectedFound { expected, .. })),
746 ) if rhs.hir_id == expr.hir_id && !expected.is_closure() => {
747 let mut primary_span = lhs.span;
750 let mut secondary_span = lhs.span;
751 let mut post_message = "";
752 match lhs.kind {
753 hir::ExprKind::Path(hir::QPath::Resolved(
754 None,
755 hir::Path {
756 res: hir::def::Res::Def(DefKind::Static { .. } | DefKind::Const, def_id),
757 ..
758 },
759 )) => {
760 if let Some(hir::Node::Item(hir::Item {
761 kind:
762 hir::ItemKind::Static(_, ident, ty, _)
763 | hir::ItemKind::Const(ident, _, ty, _),
764 ..
765 })) = self.tcx.hir_get_if_local(*def_id)
766 {
767 primary_span = ty.span;
768 secondary_span = ident.span;
769 post_message = " type";
770 }
771 }
772 hir::ExprKind::Path(hir::QPath::Resolved(
773 None,
774 hir::Path { res: hir::def::Res::Local(hir_id), .. },
775 )) => {
776 if let hir::Node::Pat(pat) = self.tcx.hir_node(*hir_id) {
777 primary_span = pat.span;
778 secondary_span = pat.span;
779 match self.tcx.parent_hir_node(pat.hir_id) {
780 hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), .. }) => {
781 primary_span = ty.span;
782 post_message = " type";
783 }
784 hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) => {
785 primary_span = init.span;
786 post_message = " value";
787 }
788 hir::Node::Param(hir::Param { ty_span, .. }) => {
789 primary_span = *ty_span;
790 post_message = " parameter type";
791 }
792 _ => {}
793 }
794 }
795 }
796 _ => {}
797 }
798
799 if primary_span != secondary_span
800 && self
801 .tcx
802 .sess
803 .source_map()
804 .is_multiline(secondary_span.shrink_to_hi().until(primary_span))
805 {
806 err.span_label(secondary_span, "expected due to the type of this binding");
809 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}"));
810 } else if post_message.is_empty() {
811 err.span_label(primary_span, "expected due to the type of this binding");
813 } else {
814 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}"));
816 }
817
818 if !lhs.is_syntactic_place_expr() {
819 err.downgrade_to_delayed_bug();
822 }
823 }
824 (
825 hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(_, lhs, rhs), .. }),
826 Some(TypeError::Sorts(ExpectedFound { expected, .. })),
827 ) if rhs.hir_id == expr.hir_id
828 && self.typeck_results.borrow().expr_ty_adjusted_opt(lhs) == Some(expected)
829 && !#[allow(non_exhaustive_omitted_patterns)] match lhs.kind {
hir::ExprKind::Let(..) => true,
_ => false,
}matches!(lhs.kind, hir::ExprKind::Let(..)) =>
831 {
832 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}`"));
833 }
834 _ => {}
835 }
836 }
837
838 fn annotate_mut_binding_to_immutable_binding(
857 &self,
858 err: &mut Diag<'_>,
859 expr: &hir::Expr<'_>,
860 expr_ty: Ty<'tcx>,
861 expected: Ty<'tcx>,
862 error: Option<TypeError<'tcx>>,
863 ) -> bool {
864 if let Some(TypeError::Sorts(ExpectedFound { .. })) = error
865 && let ty::Ref(_, inner, hir::Mutability::Not) = expected.kind()
866
867 && self.can_eq(self.param_env, *inner, expr_ty)
869
870 && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }) =
872 self.tcx.parent_hir_node(expr.hir_id)
873 && rhs.hir_id == expr.hir_id
874
875 && let hir::ExprKind::Path(hir::QPath::Resolved(
877 None,
878 hir::Path { res: hir::def::Res::Local(hir_id), .. },
879 )) = lhs.kind
880 && let hir::Node::Pat(pat) = self.tcx.hir_node(*hir_id)
881
882 && let hir::Node::Param(hir::Param { ty_span, .. }) =
884 self.tcx.parent_hir_node(pat.hir_id)
885 && let item = self.tcx.hir_get_parent_item(pat.hir_id)
886 && let item = self.tcx.hir_owner_node(item)
887 && let Some(fn_decl) = item.fn_decl()
888
889 && let hir::PatKind::Binding(hir::BindingMode::MUT, _hir_id, ident, _) = pat.kind
891
892 && let Some(ty_ref) = fn_decl
894 .inputs
895 .iter()
896 .filter_map(|ty| match ty.kind {
897 hir::TyKind::Ref(lt, inner_ty, mutbl) if ty.span == *ty_span => Some((lt, inner_ty, mutbl)),
898 _ => None,
899 })
900 .next()
901 {
902 let mut sugg = if ty_ref.2.is_mut() {
903 ::alloc::vec::Vec::new()vec![]
905 } else {
906 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(ty_ref.1.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![(
908 ty_ref.1.span.shrink_to_lo(),
909 format!("{}mut ", if ty_ref.0.ident.span.is_empty() { "" } else { " " },),
910 )]
911 };
912 sugg.extend([
913 (pat.span.until(ident.span), String::new()),
914 (lhs.span.shrink_to_lo(), "*".to_string()),
915 ]);
916 err.multipart_suggestion(
919 "you might have meant to mutate the pointed at value being passed in, instead of \
920 changing the reference in the local binding",
921 sugg,
922 Applicability::MaybeIncorrect,
923 );
924 return true;
925 }
926 false
927 }
928
929 fn annotate_alternative_method_deref_for_unop(
930 &self,
931 err: &mut Diag<'_>,
932 expr: &hir::Expr<'_>,
933 error: Option<TypeError<'tcx>>,
934 ) {
935 let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {
936 return;
937 };
938 let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }) =
939 self.tcx.parent_hir_node(expr.hir_id)
940 else {
941 return;
942 };
943 if rhs.hir_id != expr.hir_id || expected.is_closure() {
944 return;
945 }
946 let hir::ExprKind::Unary(hir::UnOp::Deref, deref) = lhs.kind else {
947 return;
948 };
949 self.annotate_alternative_method_deref(err, deref, Some(expected))
950 }
951
952 {}
#[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("annotate_alternative_method_deref",
"rustc_hir_typeck::demand", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/28221559263a3976766cf305940e80e30cf9ba8a/compiler/rustc_hir_typeck/src/demand.rs"),
::tracing_core::__macro_support::Option::Some(952u32),
::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("expr")
}> =
::tracing::__macro_support::FieldName::new("expr");
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(&expr)
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: () = loop {};
return __tracing_attr_fake_return;
}
{
let hir::ExprKind::MethodCall(path, base, args, _) =
expr.kind else { return; };
let Some(self_ty) =
self.typeck_results.borrow().expr_ty_adjusted_opt(base) else {
return;
};
let Ok(pick) =
self.lookup_probe_for_diagnostic(path.ident, self_ty, expr,
probe::ProbeScope::TraitsInScope, None) else { return; };
let Ok(in_scope_methods) =
self.probe_for_name_many(probe::Mode::MethodCall, path.ident,
expected, probe::IsSuggestion(true), self_ty, expr.hir_id,
probe::ProbeScope::TraitsInScope) else { return; };
let other_methods_in_scope: Vec<_> =
in_scope_methods.iter().filter(|c|
c.item.def_id != pick.item.def_id).collect();
let Ok(all_methods) =
self.probe_for_name_many(probe::Mode::MethodCall, path.ident,
expected, probe::IsSuggestion(true), self_ty, expr.hir_id,
probe::ProbeScope::AllTraits) else { return; };
let suggestions: Vec<_> =
all_methods.into_iter().filter_map(|c|
{
if c.item.def_id == pick.item.def_id { return None; }
let m = c.item;
let generic_args =
ty::GenericArgs::for_item(self.tcx, m.def_id,
|param, _| { self.var_for_def(expr.span, param) });
let fn_sig = self.tcx.fn_sig(m.def_id);
if fn_sig.skip_binder().inputs().skip_binder().len() !=
args.len() + 1 {
return None;
}
let rcvr_ty = fn_sig.skip_binder().input(0).skip_binder();
let (mutability, ty) =
match rcvr_ty.kind() {
ty::Ref(_, ty, hir::Mutability::Mut) => ("&mut ", ty),
ty::Ref(_, ty, _) => ("&", ty),
_ => ("", &rcvr_ty),
};
let path =
match self.tcx.assoc_parent(m.def_id) {
Some((_, DefKind::Impl { of_trait: true })) => {
self.tcx.def_path_str_with_args(m.def_id,
generic_args).to_string()
}
Some((_, DefKind::Impl { of_trait: false })) => {
if let ty::Adt(def, _) = ty.kind() {
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}",
self.tcx.def_path_str(def.did()), path.ident))
})
} else {
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{1}::{0}", path.ident,
ty))
})
}
}
_ =>
{
let _guard = NoTrimmedGuard::new();
self.tcx.def_path_str_with_args(m.def_id, generic_args)
}.to_string(),
};
Some(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(expr.span.until(base.span),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{1}({0}", mutability,
path))
})),
match &args {
[] =>
(base.span.shrink_to_hi().with_hi(expr.span.hi()),
")".to_string()),
[first, ..] =>
(base.span.between(first.span), ", ".to_string()),
}])))
}).collect();
if suggestions.is_empty() { return; }
let mut path_span: MultiSpan = path.ident.span.into();
path_span.push_span_label(path.ident.span,
{
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)))
})
});
let container_id = pick.item.container_id(self.tcx);
let container =
{
let _guard = NoTrimmedGuard::new();
self.tcx.def_path_str(container_id)
};
for &def_id in pick.import_ids {
let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
path_span.push_span_label(self.tcx.hir_span(hir_id),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` imported here",
container))
}));
}
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()))
}),
}
};
err.span_note(path_span,
::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))
}));
if suggestions.len() > other_methods_in_scope.len() {
let n = suggestions.len() - other_methods_in_scope.len();
err.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("additionally, there {0} {2} other available method{1} that {0}n\'t in scope",
if n == 1 { "is" } else { "are" },
if n == 1 { "" } else { "s" }, n))
}));
}
err.multipart_suggestions(::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" }))
}), suggestions, Applicability::MaybeIncorrect);
}
}
}#[tracing::instrument(skip(self, err), level = "debug")]
953 pub(crate) fn annotate_alternative_method_deref(
954 &self,
955 err: &mut Diag<'_>,
956 expr: &hir::Expr<'_>,
957 expected: Option<Ty<'tcx>>,
958 ) {
959 let hir::ExprKind::MethodCall(path, base, args, _) = expr.kind else {
960 return;
961 };
962 let Some(self_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(base) else {
963 return;
964 };
965
966 let Ok(pick) = self.lookup_probe_for_diagnostic(
967 path.ident,
968 self_ty,
969 expr,
970 probe::ProbeScope::TraitsInScope,
971 None,
972 ) else {
973 return;
974 };
975
976 let Ok(in_scope_methods) = self.probe_for_name_many(
977 probe::Mode::MethodCall,
978 path.ident,
979 expected,
980 probe::IsSuggestion(true),
981 self_ty,
982 expr.hir_id,
983 probe::ProbeScope::TraitsInScope,
984 ) else {
985 return;
986 };
987
988 let other_methods_in_scope: Vec<_> =
989 in_scope_methods.iter().filter(|c| c.item.def_id != pick.item.def_id).collect();
990
991 let Ok(all_methods) = self.probe_for_name_many(
992 probe::Mode::MethodCall,
993 path.ident,
994 expected,
995 probe::IsSuggestion(true),
996 self_ty,
997 expr.hir_id,
998 probe::ProbeScope::AllTraits,
999 ) else {
1000 return;
1001 };
1002
1003 let suggestions: Vec<_> = all_methods
1004 .into_iter()
1005 .filter_map(|c| {
1006 if c.item.def_id == pick.item.def_id {
1007 return None;
1008 }
1009 let m = c.item;
1010 let generic_args = ty::GenericArgs::for_item(self.tcx, m.def_id, |param, _| {
1011 self.var_for_def(expr.span, param)
1012 });
1013 let fn_sig = self.tcx.fn_sig(m.def_id);
1014 if fn_sig.skip_binder().inputs().skip_binder().len() != args.len() + 1 {
1015 return None;
1016 }
1017 let rcvr_ty = fn_sig.skip_binder().input(0).skip_binder();
1018 let (mutability, ty) = match rcvr_ty.kind() {
1019 ty::Ref(_, ty, hir::Mutability::Mut) => ("&mut ", ty),
1020 ty::Ref(_, ty, _) => ("&", ty),
1021 _ => ("", &rcvr_ty),
1022 };
1023 let path = match self.tcx.assoc_parent(m.def_id) {
1024 Some((_, DefKind::Impl { of_trait: true })) => {
1025 self.tcx.def_path_str_with_args(m.def_id, generic_args).to_string()
1027 }
1028 Some((_, DefKind::Impl { of_trait: false })) => {
1029 if let ty::Adt(def, _) = ty.kind() {
1030 format!("{}::{}", self.tcx.def_path_str(def.did()), path.ident)
1032 } else {
1033 format!("{ty}::{}", path.ident)
1035 }
1036 }
1037 _ => with_no_trimmed_paths!(
1039 self.tcx.def_path_str_with_args(m.def_id, generic_args)
1040 )
1041 .to_string(),
1042 };
1043 Some(vec![
1044 (expr.span.until(base.span), format!("{path}({}", mutability)),
1045 match &args {
1046 [] => (base.span.shrink_to_hi().with_hi(expr.span.hi()), ")".to_string()),
1047 [first, ..] => (base.span.between(first.span), ", ".to_string()),
1048 },
1049 ])
1050 })
1051 .collect();
1052 if suggestions.is_empty() {
1053 return;
1054 }
1055 let mut path_span: MultiSpan = path.ident.span.into();
1056 path_span.push_span_label(
1057 path.ident.span,
1058 with_no_trimmed_paths!(format!(
1059 "refers to `{}`",
1060 self.tcx.def_path_str(pick.item.def_id),
1061 )),
1062 );
1063 let container_id = pick.item.container_id(self.tcx);
1064 let container = with_no_trimmed_paths!(self.tcx.def_path_str(container_id));
1065 for &def_id in pick.import_ids {
1066 let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
1067 path_span
1068 .push_span_label(self.tcx.hir_span(hir_id), format!("`{container}` imported here"));
1069 }
1070 let tail = with_no_trimmed_paths!(match &other_methods_in_scope[..] {
1071 [] => return,
1072 [candidate] => format!(
1073 "the method of the same name on {} `{}`",
1074 match candidate.kind {
1075 probe::CandidateKind::InherentImplCandidate { .. } => "the inherent impl for",
1076 _ => "trait",
1077 },
1078 self.tcx.def_path_str(candidate.item.container_id(self.tcx))
1079 ),
1080 _ if other_methods_in_scope.len() < 5 => {
1081 format!(
1082 "the methods of the same name on {}",
1083 listify(
1084 &other_methods_in_scope[..other_methods_in_scope.len() - 1],
1085 |c| format!("`{}`", self.tcx.def_path_str(c.item.container_id(self.tcx)))
1086 )
1087 .unwrap_or_default(),
1088 )
1089 }
1090 _ => format!(
1091 "the methods of the same name on {} other traits",
1092 other_methods_in_scope.len()
1093 ),
1094 });
1095 err.span_note(
1096 path_span,
1097 format!(
1098 "the `{}` call is resolved to the method in `{container}`, shadowing {tail}",
1099 path.ident,
1100 ),
1101 );
1102 if suggestions.len() > other_methods_in_scope.len() {
1103 let n = suggestions.len() - other_methods_in_scope.len();
1104 err.note(format!(
1105 "additionally, there {are} {n} other available method{s} that {are}n't in scope",
1106 are = pluralize!("is", n),
1107 s = pluralize!(n),
1108 ));
1109 }
1110 err.multipart_suggestions(
1111 format!(
1112 "you might have meant to call {}; you can use the fully-qualified path to call {} \
1113 explicitly",
1114 if suggestions.len() == 1 {
1115 "the other method"
1116 } else {
1117 "one of the other methods"
1118 },
1119 if suggestions.len() == 1 { "it" } else { "one of them" },
1120 ),
1121 suggestions,
1122 Applicability::MaybeIncorrect,
1123 );
1124 }
1125
1126 pub(crate) fn get_conversion_methods_for_diagnostic(
1127 &self,
1128 span: Span,
1129 expected: Ty<'tcx>,
1130 checked_ty: Ty<'tcx>,
1131 hir_id: hir::HirId,
1132 ) -> Vec<AssocItem> {
1133 let methods = self.probe_for_return_type_for_diagnostic(
1134 span,
1135 probe::Mode::MethodCall,
1136 expected,
1137 checked_ty,
1138 hir_id,
1139 |m| {
1140 self.has_only_self_parameter(m)
1141 && {
{
'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)
1152 },
1153 );
1154
1155 methods
1156 }
1157
1158 fn has_only_self_parameter(&self, method: &AssocItem) -> bool {
1160 method.is_method()
1161 && self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len() == 1
1162 }
1163
1164 pub(crate) fn maybe_get_block_expr(
1166 &self,
1167 expr: &hir::Expr<'tcx>,
1168 ) -> Option<&'tcx hir::Expr<'tcx>> {
1169 match expr {
1170 hir::Expr { kind: hir::ExprKind::Block(block, ..), .. } => block.expr,
1171 _ => None,
1172 }
1173 }
1174
1175 pub(crate) fn is_destruct_assignment_desugaring(&self, expr: &hir::Expr<'_>) -> bool {
1180 if let hir::ExprKind::Path(hir::QPath::Resolved(
1181 _,
1182 hir::Path { res: hir::def::Res::Local(bind_hir_id), .. },
1183 )) = expr.kind
1184 && let bind = self.tcx.hir_node(*bind_hir_id)
1185 && let parent = self.tcx.parent_hir_node(*bind_hir_id)
1186 && let hir::Node::Pat(hir::Pat {
1187 kind: hir::PatKind::Binding(_, _hir_id, _, _), ..
1188 }) = bind
1189 && let hir::Node::Pat(hir::Pat { default_binding_modes: false, .. }) = parent
1190 {
1191 true
1192 } else {
1193 false
1194 }
1195 }
1196
1197 fn explain_self_literal(
1198 &self,
1199 err: &mut Diag<'_>,
1200 expr: &hir::Expr<'tcx>,
1201 expected: Ty<'tcx>,
1202 found: Ty<'tcx>,
1203 ) {
1204 match expr.peel_drop_temps().kind {
1205 hir::ExprKind::Struct(
1206 hir::QPath::Resolved(
1207 None,
1208 hir::Path { res: hir::def::Res::SelfTyAlias { alias_to, .. }, span, .. },
1209 ),
1210 ..,
1211 )
1212 | hir::ExprKind::Call(
1213 hir::Expr {
1214 kind:
1215 hir::ExprKind::Path(hir::QPath::Resolved(
1216 None,
1217 hir::Path {
1218 res: hir::def::Res::SelfTyAlias { alias_to, .. },
1219 span,
1220 ..
1221 },
1222 )),
1223 ..
1224 },
1225 ..,
1226 ) => {
1227 if let Some(hir::Node::Item(hir::Item {
1228 kind: hir::ItemKind::Impl(hir::Impl { self_ty, .. }),
1229 ..
1230 })) = self.tcx.hir_get_if_local(*alias_to)
1231 {
1232 err.span_label(self_ty.span, "this is the type of the `Self` literal");
1233 }
1234 if let ty::Adt(e_def, e_args) = expected.kind()
1235 && let ty::Adt(f_def, _f_args) = found.kind()
1236 && e_def == f_def
1237 {
1238 err.span_suggestion_verbose(
1239 *span,
1240 "use the type name directly",
1241 self.tcx.value_path_str_with_args(e_def.did(), e_args),
1242 Applicability::MaybeIncorrect,
1243 );
1244 }
1245 }
1246 _ => {}
1247 }
1248 }
1249
1250 fn note_wrong_return_ty_due_to_generic_arg(
1251 &self,
1252 err: &mut Diag<'_>,
1253 expr: &hir::Expr<'_>,
1254 checked_ty: Ty<'tcx>,
1255 ) {
1256 let hir::Node::Expr(parent_expr) = self.tcx.parent_hir_node(expr.hir_id) else {
1257 return;
1258 };
1259 if parent_expr.span.desugaring_kind().is_some() {
1260 return;
1261 }
1262 enum CallableKind {
1263 Function,
1264 Method,
1265 Constructor,
1266 }
1267 let mut maybe_emit_help = |def_id: hir::def_id::DefId,
1268 callable: Ident,
1269 args: &[hir::Expr<'_>],
1270 kind: CallableKind| {
1271 let arg_idx = args.iter().position(|a| a.hir_id == expr.hir_id).unwrap();
1272 let fn_ty = self.tcx.type_of(def_id).skip_binder();
1273 if !fn_ty.is_fn() {
1274 return;
1275 }
1276 let fn_sig = fn_ty.fn_sig(self.tcx).skip_binder();
1277 let Some(&arg) = fn_sig
1278 .inputs()
1279 .get(arg_idx + if #[allow(non_exhaustive_omitted_patterns)] match kind {
CallableKind::Method => true,
_ => false,
}matches!(kind, CallableKind::Method) { 1 } else { 0 })
1280 else {
1281 return;
1282 };
1283 if #[allow(non_exhaustive_omitted_patterns)] match arg.kind() {
ty::Param(_) => true,
_ => false,
}matches!(arg.kind(), ty::Param(_))
1284 && fn_sig.output().contains(arg)
1285 && self.node_ty(args[arg_idx].hir_id) == checked_ty
1286 {
1287 let mut multi_span: MultiSpan = parent_expr.span.into();
1288 multi_span.push_span_label(
1289 args[arg_idx].span,
1290 ::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!(
1291 "this argument influences the {} of `{}`",
1292 if matches!(kind, CallableKind::Constructor) {
1293 "type"
1294 } else {
1295 "return type"
1296 },
1297 callable
1298 ),
1299 );
1300 err.span_help(
1301 multi_span,
1302 ::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!(
1303 "the {} `{}` due to the type of the argument passed",
1304 match kind {
1305 CallableKind::Function => "return type of this call is",
1306 CallableKind::Method => "return type of this call is",
1307 CallableKind::Constructor => "type constructed contains",
1308 },
1309 checked_ty
1310 ),
1311 );
1312 }
1313 };
1314 match parent_expr.kind {
1315 hir::ExprKind::Call(fun, args) => {
1316 let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else {
1317 return;
1318 };
1319 let hir::def::Res::Def(kind, def_id) = path.res else {
1320 return;
1321 };
1322 let callable_kind = if #[allow(non_exhaustive_omitted_patterns)] match kind {
DefKind::Ctor(_, _) => true,
_ => false,
}matches!(kind, DefKind::Ctor(_, _)) {
1323 CallableKind::Constructor
1324 } else {
1325 CallableKind::Function
1326 };
1327 maybe_emit_help(def_id, path.segments.last().unwrap().ident, args, callable_kind);
1328 }
1329 hir::ExprKind::MethodCall(method, _receiver, args, _span) => {
1330 let Some(def_id) =
1331 self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id)
1332 else {
1333 return;
1334 };
1335 maybe_emit_help(def_id, method.ident, args, CallableKind::Method)
1336 }
1337 _ => return,
1338 }
1339 }
1340}
1341
1342pub(crate) enum TypeMismatchSource<'tcx> {
1343 Ty(Ty<'tcx>),
1346 Arg { call_expr: &'tcx hir::Expr<'tcx>, incompatible_arg: usize },
1350}