1 use crate::FnCtxt; 2 use rustc_ast::util::parser::PREC_POSTFIX; 3 use rustc_errors::MultiSpan; 4 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; 5 use rustc_hir as hir; 6 use rustc_hir::def::{CtorKind, Res}; 7 use rustc_hir::intravisit::Visitor; 8 use rustc_hir::lang_items::LangItem; 9 use rustc_hir::{is_range_literal, Node}; 10 use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; 11 use rustc_middle::lint::in_external_macro; 12 use rustc_middle::middle::stability::EvalResult; 13 use rustc_middle::ty::adjustment::AllowTwoPhase; 14 use rustc_middle::ty::error::{ExpectedFound, TypeError}; 15 use rustc_middle::ty::fold::BottomUpFolder; 16 use rustc_middle::ty::print::with_no_trimmed_paths; 17 use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeFoldable}; 18 use rustc_span::symbol::{sym, Symbol}; 19 use rustc_span::{BytePos, Span, DUMMY_SP}; 20 use rustc_trait_selection::infer::InferCtxtExt as _; 21 use rustc_trait_selection::traits::ObligationCause; 22 23 use super::method::probe; 24 25 use std::cmp::min; 26 use std::iter; 27 28 impl<'a, 'tcx> FnCtxt<'a, 'tcx> { emit_type_mismatch_suggestions( &self, err: &mut Diagnostic, expr: &hir::Expr<'tcx>, expr_ty: Ty<'tcx>, expected: Ty<'tcx>, expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, error: Option<TypeError<'tcx>>, )29 pub fn emit_type_mismatch_suggestions( 30 &self, 31 err: &mut Diagnostic, 32 expr: &hir::Expr<'tcx>, 33 expr_ty: Ty<'tcx>, 34 expected: Ty<'tcx>, 35 expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, 36 error: Option<TypeError<'tcx>>, 37 ) { 38 if expr_ty == expected { 39 return; 40 } 41 42 self.annotate_alternative_method_deref(err, expr, error); 43 44 // Use `||` to give these suggestions a precedence 45 let suggested = self.suggest_missing_parentheses(err, expr) 46 || self.suggest_remove_last_method_call(err, expr, expected) 47 || self.suggest_associated_const(err, expr, expected) 48 || self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr) 49 || self.suggest_option_to_bool(err, expr, expr_ty, expected) 50 || self.suggest_compatible_variants(err, expr, expected, expr_ty) 51 || self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty) 52 || self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) 53 || self.suggest_no_capture_closure(err, expected, expr_ty) 54 || self.suggest_boxing_when_appropriate(err, expr.span, expr.hir_id, expected, expr_ty) 55 || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected) 56 || self.suggest_copied_or_cloned(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 63 if !suggested { 64 self.note_source_of_type_mismatch_constraint( 65 err, 66 expr, 67 TypeMismatchSource::Ty(expected), 68 ); 69 } 70 } 71 emit_coerce_suggestions( &self, err: &mut Diagnostic, expr: &hir::Expr<'tcx>, expr_ty: Ty<'tcx>, expected: Ty<'tcx>, expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, error: Option<TypeError<'tcx>>, )72 pub fn emit_coerce_suggestions( 73 &self, 74 err: &mut Diagnostic, 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 87 if self.is_destruct_assignment_desugaring(expr) { 88 return; 89 } 90 self.emit_type_mismatch_suggestions(err, expr, expr_ty, expected, expected_ty_expr, error); 91 self.note_type_is_not_clone(err, expected, expr_ty, expr); 92 self.note_internal_mutation_in_method(err, expr, Some(expected), expr_ty); 93 self.suggest_method_call_on_range_literal(err, expr, expr_ty, expected); 94 self.suggest_return_binding_for_missing_tail_expr(err, expr, expr_ty, expected); 95 self.note_wrong_return_ty_due_to_generic_arg(err, expr, expr_ty); 96 } 97 98 /// Really hacky heuristic to remap an `assert_eq!` error to the user 99 /// expressions provided to the macro. adjust_expr_for_assert_eq_macro( &self, found_expr: &mut &'tcx hir::Expr<'tcx>, expected_expr: &mut Option<&'tcx hir::Expr<'tcx>>, )100 fn adjust_expr_for_assert_eq_macro( 101 &self, 102 found_expr: &mut &'tcx hir::Expr<'tcx>, 103 expected_expr: &mut Option<&'tcx hir::Expr<'tcx>>, 104 ) { 105 let Some(expected_expr) = expected_expr else { return; }; 106 107 if !found_expr.span.eq_ctxt(expected_expr.span) { 108 return; 109 } 110 111 if !found_expr 112 .span 113 .ctxt() 114 .outer_expn_data() 115 .macro_def_id 116 .is_some_and(|def_id| self.tcx.is_diagnostic_item(sym::assert_eq_macro, def_id)) 117 { 118 return; 119 } 120 121 let hir::ExprKind::Unary( 122 hir::UnOp::Deref, 123 hir::Expr { kind: hir::ExprKind::Path(found_path), .. }, 124 ) = found_expr.kind else { return; }; 125 let hir::ExprKind::Unary( 126 hir::UnOp::Deref, 127 hir::Expr { kind: hir::ExprKind::Path(expected_path), .. }, 128 ) = expected_expr.kind else { return; }; 129 130 for (path, name, idx, var) in [ 131 (expected_path, "left_val", 0, expected_expr), 132 (found_path, "right_val", 1, found_expr), 133 ] { 134 if let hir::QPath::Resolved(_, path) = path 135 && let [segment] = path.segments 136 && segment.ident.name.as_str() == name 137 && let Res::Local(hir_id) = path.res 138 && let Some((_, hir::Node::Expr(match_expr))) = self.tcx.hir().parent_iter(hir_id).nth(2) 139 && let hir::ExprKind::Match(scrutinee, _, _) = match_expr.kind 140 && let hir::ExprKind::Tup(exprs) = scrutinee.kind 141 && let hir::ExprKind::AddrOf(_, _, macro_arg) = exprs[idx].kind 142 { 143 *var = macro_arg; 144 } 145 } 146 } 147 148 /// Requires that the two types unify, and prints an error message if 149 /// they don't. demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>)150 pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { 151 if let Some(mut e) = self.demand_suptype_diag(sp, expected, actual) { 152 e.emit(); 153 } 154 } 155 demand_suptype_diag( &self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>156 pub fn demand_suptype_diag( 157 &self, 158 sp: Span, 159 expected: Ty<'tcx>, 160 actual: Ty<'tcx>, 161 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { 162 self.demand_suptype_with_origin(&self.misc(sp), expected, actual) 163 } 164 165 #[instrument(skip(self), level = "debug")] demand_suptype_with_origin( &self, cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>166 pub fn demand_suptype_with_origin( 167 &self, 168 cause: &ObligationCause<'tcx>, 169 expected: Ty<'tcx>, 170 actual: Ty<'tcx>, 171 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { 172 match self.at(cause, self.param_env).sup(DefineOpaqueTypes::Yes, expected, actual) { 173 Ok(InferOk { obligations, value: () }) => { 174 self.register_predicates(obligations); 175 None 176 } 177 Err(e) => Some(self.err_ctxt().report_mismatched_types(&cause, expected, actual, e)), 178 } 179 } 180 demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>)181 pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { 182 if let Some(mut err) = self.demand_eqtype_diag(sp, expected, actual) { 183 err.emit(); 184 } 185 } 186 demand_eqtype_diag( &self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>187 pub fn demand_eqtype_diag( 188 &self, 189 sp: Span, 190 expected: Ty<'tcx>, 191 actual: Ty<'tcx>, 192 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { 193 self.demand_eqtype_with_origin(&self.misc(sp), expected, actual) 194 } 195 demand_eqtype_with_origin( &self, cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>196 pub fn demand_eqtype_with_origin( 197 &self, 198 cause: &ObligationCause<'tcx>, 199 expected: Ty<'tcx>, 200 actual: Ty<'tcx>, 201 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { 202 match self.at(cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, actual) { 203 Ok(InferOk { obligations, value: () }) => { 204 self.register_predicates(obligations); 205 None 206 } 207 Err(e) => Some(self.err_ctxt().report_mismatched_types(cause, expected, actual, e)), 208 } 209 } 210 demand_coerce( &self, expr: &'tcx hir::Expr<'tcx>, checked_ty: Ty<'tcx>, expected: Ty<'tcx>, expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, allow_two_phase: AllowTwoPhase, ) -> Ty<'tcx>211 pub fn demand_coerce( 212 &self, 213 expr: &'tcx hir::Expr<'tcx>, 214 checked_ty: Ty<'tcx>, 215 expected: Ty<'tcx>, 216 expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, 217 allow_two_phase: AllowTwoPhase, 218 ) -> Ty<'tcx> { 219 let (ty, err) = 220 self.demand_coerce_diag(expr, checked_ty, expected, expected_ty_expr, allow_two_phase); 221 if let Some(mut err) = err { 222 err.emit(); 223 } 224 ty 225 } 226 227 /// Checks that the type of `expr` can be coerced to `expected`. 228 /// 229 /// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!` 230 /// will be permitted if the diverges flag is currently "always". 231 #[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))] demand_coerce_diag( &self, mut expr: &'tcx hir::Expr<'tcx>, checked_ty: Ty<'tcx>, expected: Ty<'tcx>, mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, allow_two_phase: AllowTwoPhase, ) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>)232 pub fn demand_coerce_diag( 233 &self, 234 mut expr: &'tcx hir::Expr<'tcx>, 235 checked_ty: Ty<'tcx>, 236 expected: Ty<'tcx>, 237 mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, 238 allow_two_phase: AllowTwoPhase, 239 ) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>) { 240 let expected = self.resolve_vars_with_obligations(expected); 241 242 let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase, None) { 243 Ok(ty) => return (ty, None), 244 Err(e) => e, 245 }; 246 247 self.adjust_expr_for_assert_eq_macro(&mut expr, &mut expected_ty_expr); 248 249 self.set_tainted_by_errors(self.tcx.sess.delay_span_bug( 250 expr.span, 251 "`TypeError` when attempting coercion but no error emitted", 252 )); 253 let expr = expr.peel_drop_temps(); 254 let cause = self.misc(expr.span); 255 let expr_ty = self.resolve_vars_with_obligations(checked_ty); 256 let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e); 257 258 let is_insufficiently_polymorphic = 259 matches!(e, TypeError::RegionsInsufficientlyPolymorphic(..)); 260 261 // FIXME(#73154): For now, we do leak check when coercing function 262 // pointers in typeck, instead of only during borrowck. This can lead 263 // to these `RegionsInsufficientlyPolymorphic` errors that aren't helpful. 264 if !is_insufficiently_polymorphic { 265 self.emit_coerce_suggestions( 266 &mut err, 267 expr, 268 expr_ty, 269 expected, 270 expected_ty_expr, 271 Some(e), 272 ); 273 } 274 275 (expected, Some(err)) 276 } 277 278 /// Notes the point at which a variable is constrained to some type incompatible 279 /// with some expectation given by `source`. note_source_of_type_mismatch_constraint( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, source: TypeMismatchSource<'tcx>, ) -> bool280 pub fn note_source_of_type_mismatch_constraint( 281 &self, 282 err: &mut Diagnostic, 283 expr: &hir::Expr<'_>, 284 source: TypeMismatchSource<'tcx>, 285 ) -> bool { 286 let hir = self.tcx.hir(); 287 288 let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind else { return false; }; 289 let [hir::PathSegment { ident, args: None, .. }] = p.segments else { return false; }; 290 let hir::def::Res::Local(local_hir_id) = p.res else { return false; }; 291 let hir::Node::Pat(pat) = hir.get(local_hir_id) else { return false; }; 292 let (init_ty_hir_id, init) = match hir.get_parent(pat.hir_id) { 293 hir::Node::Local(hir::Local { ty: Some(ty), init, .. }) => (ty.hir_id, *init), 294 hir::Node::Local(hir::Local { init: Some(init), .. }) => (init.hir_id, Some(*init)), 295 _ => return false, 296 }; 297 let Some(init_ty) = self.node_ty_opt(init_ty_hir_id) else { return false; }; 298 299 // Locate all the usages of the relevant binding. 300 struct FindExprs<'tcx> { 301 hir_id: hir::HirId, 302 uses: Vec<&'tcx hir::Expr<'tcx>>, 303 } 304 impl<'tcx> Visitor<'tcx> for FindExprs<'tcx> { 305 fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { 306 if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = ex.kind 307 && let hir::def::Res::Local(hir_id) = path.res 308 && hir_id == self.hir_id 309 { 310 self.uses.push(ex); 311 } 312 hir::intravisit::walk_expr(self, ex); 313 } 314 } 315 316 let mut expr_finder = FindExprs { hir_id: local_hir_id, uses: init.into_iter().collect() }; 317 let body = 318 hir.body(hir.maybe_body_owned_by(self.body_id).expect("expected item to have body")); 319 expr_finder.visit_expr(body.value); 320 321 use rustc_infer::infer::type_variable::*; 322 use rustc_middle::infer::unify_key::*; 323 // Replaces all of the variables in the given type with a fresh inference variable. 324 let mut fudger = BottomUpFolder { 325 tcx: self.tcx, 326 ty_op: |ty| { 327 if let ty::Infer(infer) = ty.kind() { 328 match infer { 329 ty::InferTy::TyVar(_) => self.next_ty_var(TypeVariableOrigin { 330 kind: TypeVariableOriginKind::MiscVariable, 331 span: DUMMY_SP, 332 }), 333 ty::InferTy::IntVar(_) => self.next_int_var(), 334 ty::InferTy::FloatVar(_) => self.next_float_var(), 335 _ => bug!(), 336 } 337 } else { 338 ty 339 } 340 }, 341 lt_op: |_| self.tcx.lifetimes.re_erased, 342 ct_op: |ct| { 343 if let ty::ConstKind::Infer(_) = ct.kind() { 344 self.next_const_var( 345 ct.ty(), 346 ConstVariableOrigin { 347 kind: ConstVariableOriginKind::MiscVariable, 348 span: DUMMY_SP, 349 }, 350 ) 351 } else { 352 ct 353 } 354 }, 355 }; 356 357 let expected_ty = match source { 358 TypeMismatchSource::Ty(expected_ty) => expected_ty, 359 // Try to deduce what the possible value of `expr` would be if the 360 // incompatible arg were compatible. For example, given `Vec<i32>` 361 // and `vec.push(1u32)`, we ideally want to deduce that the type of 362 // `vec` *should* have been `Vec<u32>`. This will allow us to then 363 // run the subsequent code with this expectation, finding out exactly 364 // when this type diverged from our expectation. 365 TypeMismatchSource::Arg { call_expr, incompatible_arg: idx } => { 366 let hir::ExprKind::MethodCall(segment, _, args, _) = call_expr.kind else { 367 return false; 368 }; 369 let Some(arg_ty) = self.node_ty_opt(args[idx].hir_id) else { 370 return false; 371 }; 372 let possible_rcvr_ty = expr_finder.uses.iter().find_map(|binding| { 373 let possible_rcvr_ty = self.node_ty_opt(binding.hir_id)?; 374 // Fudge the receiver, so we can do new inference on it. 375 let possible_rcvr_ty = possible_rcvr_ty.fold_with(&mut fudger); 376 let method = self 377 .lookup_method_for_diagnostic( 378 possible_rcvr_ty, 379 segment, 380 DUMMY_SP, 381 call_expr, 382 binding, 383 ) 384 .ok()?; 385 // Unify the method signature with our incompatible arg, to 386 // do inference in the *opposite* direction and to find out 387 // what our ideal rcvr ty would look like. 388 let _ = self 389 .at(&ObligationCause::dummy(), self.param_env) 390 .eq(DefineOpaqueTypes::No, method.sig.inputs()[idx + 1], arg_ty) 391 .ok()?; 392 self.select_obligations_where_possible(|errs| { 393 // Yeet the errors, we're already reporting errors. 394 errs.clear(); 395 }); 396 Some(self.resolve_vars_if_possible(possible_rcvr_ty)) 397 }); 398 if let Some(rcvr_ty) = possible_rcvr_ty { 399 rcvr_ty 400 } else { 401 return false; 402 } 403 } 404 }; 405 406 // If our expected_ty does not equal init_ty, then it *began* as incompatible. 407 // No need to note in this case... 408 if !self.can_eq(self.param_env, expected_ty, init_ty.fold_with(&mut fudger)) { 409 return false; 410 } 411 412 for window in expr_finder.uses.windows(2) { 413 // Bindings always update their recorded type after the fact, so we 414 // need to look at the *following* usage's type to see when the 415 // binding became incompatible. 416 let [binding, next_usage] = *window else { continue; }; 417 418 // Don't go past the binding (always gonna be a nonsense label if so) 419 if binding.hir_id == expr.hir_id { 420 break; 421 } 422 423 let Some(next_use_ty) = self.node_ty_opt(next_usage.hir_id) else { continue; }; 424 425 // If the type is not constrained in a way making it not possible to 426 // equate with `expected_ty` by this point, skip. 427 if self.can_eq(self.param_env, expected_ty, next_use_ty.fold_with(&mut fudger)) { 428 continue; 429 } 430 431 if let hir::Node::Expr(parent_expr) = hir.get_parent(binding.hir_id) 432 && let hir::ExprKind::MethodCall(segment, rcvr, args, _) = parent_expr.kind 433 && rcvr.hir_id == binding.hir_id 434 { 435 // If our binding became incompatible while it was a receiver 436 // to a method call, we may be able to make a better guess to 437 // the source of a type mismatch. 438 let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { continue; }; 439 let rcvr_ty = rcvr_ty.fold_with(&mut fudger); 440 let Ok(method) = 441 self.lookup_method_for_diagnostic(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr) 442 else { 443 continue; 444 }; 445 446 let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger); 447 let ideal_method = self 448 .lookup_method_for_diagnostic(ideal_rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr) 449 .ok() 450 .and_then(|method| { 451 let _ = self.at(&ObligationCause::dummy(), self.param_env) 452 .eq(DefineOpaqueTypes::No, ideal_rcvr_ty, expected_ty) 453 .ok()?; 454 Some(method) 455 }); 456 457 // Find what argument caused our rcvr to become incompatible 458 // with the expected ty. 459 for (idx, (expected_arg_ty, arg_expr)) in 460 std::iter::zip(&method.sig.inputs()[1..], args).enumerate() 461 { 462 let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else { continue; }; 463 let arg_ty = arg_ty.fold_with(&mut fudger); 464 let _ = self.try_coerce( 465 arg_expr, 466 arg_ty, 467 *expected_arg_ty, 468 AllowTwoPhase::No, 469 None, 470 ); 471 self.select_obligations_where_possible(|errs| { 472 // Yeet the errors, we're already reporting errors. 473 errs.clear(); 474 }); 475 // If our rcvr, after inference due to unifying the signature 476 // with the expected argument type, is still compatible with 477 // the rcvr, then it must've not been the source of blame. 478 if self.can_eq(self.param_env, rcvr_ty, expected_ty) { 479 continue; 480 } 481 err.span_label(arg_expr.span, format!("this argument has type `{arg_ty}`...")); 482 err.span_label( 483 binding.span, 484 format!("... which causes `{ident}` to have type `{next_use_ty}`"), 485 ); 486 // Using our "ideal" method signature, suggest a fix to this 487 // blame arg, if possible. Don't do this if we're coming from 488 // arg mismatch code, because we'll possibly suggest a mutually 489 // incompatible fix at the original mismatch site. 490 if matches!(source, TypeMismatchSource::Ty(_)) 491 && let Some(ideal_method) = ideal_method 492 { 493 self.emit_type_mismatch_suggestions( 494 err, 495 arg_expr, 496 arg_ty, 497 self.resolve_vars_if_possible(ideal_method.sig.inputs()[idx + 1]), 498 None, 499 None, 500 ); 501 } 502 return true; 503 } 504 } 505 err.span_label( 506 binding.span, 507 format!("here the type of `{ident}` is inferred to be `{next_use_ty}`"), 508 ); 509 return true; 510 } 511 512 // We must've not found something that constrained the expr. 513 false 514 } 515 annotate_expected_due_to_let_ty( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, error: Option<TypeError<'tcx>>, )516 fn annotate_expected_due_to_let_ty( 517 &self, 518 err: &mut Diagnostic, 519 expr: &hir::Expr<'_>, 520 error: Option<TypeError<'tcx>>, 521 ) { 522 let parent = self.tcx.hir().parent_id(expr.hir_id); 523 match (self.tcx.hir().find(parent), error) { 524 (Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })), _) 525 if init.hir_id == expr.hir_id => 526 { 527 // Point at `let` assignment type. 528 err.span_label(ty.span, "expected due to this"); 529 } 530 ( 531 Some(hir::Node::Expr(hir::Expr { 532 kind: hir::ExprKind::Assign(lhs, rhs, _), .. 533 })), 534 Some(TypeError::Sorts(ExpectedFound { expected, .. })), 535 ) if rhs.hir_id == expr.hir_id && !expected.is_closure() => { 536 // We ignore closures explicitly because we already point at them elsewhere. 537 // Point at the assigned-to binding. 538 let mut primary_span = lhs.span; 539 let mut secondary_span = lhs.span; 540 let mut post_message = ""; 541 match lhs.kind { 542 hir::ExprKind::Path(hir::QPath::Resolved( 543 None, 544 hir::Path { 545 res: 546 hir::def::Res::Def( 547 hir::def::DefKind::Static(_) | hir::def::DefKind::Const, 548 def_id, 549 ), 550 .. 551 }, 552 )) => { 553 if let Some(hir::Node::Item(hir::Item { 554 ident, 555 kind: hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..), 556 .. 557 })) = self.tcx.hir().get_if_local(*def_id) 558 { 559 primary_span = ty.span; 560 secondary_span = ident.span; 561 post_message = " type"; 562 } 563 } 564 hir::ExprKind::Path(hir::QPath::Resolved( 565 None, 566 hir::Path { res: hir::def::Res::Local(hir_id), .. }, 567 )) => { 568 if let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(*hir_id) { 569 primary_span = pat.span; 570 secondary_span = pat.span; 571 match self.tcx.hir().find_parent(pat.hir_id) { 572 Some(hir::Node::Local(hir::Local { ty: Some(ty), .. })) => { 573 primary_span = ty.span; 574 post_message = " type"; 575 } 576 Some(hir::Node::Local(hir::Local { init: Some(init), .. })) => { 577 primary_span = init.span; 578 post_message = " value"; 579 } 580 Some(hir::Node::Param(hir::Param { ty_span, .. })) => { 581 primary_span = *ty_span; 582 post_message = " parameter type"; 583 } 584 _ => {} 585 } 586 } 587 } 588 _ => {} 589 } 590 591 if primary_span != secondary_span 592 && self 593 .tcx 594 .sess 595 .source_map() 596 .is_multiline(secondary_span.shrink_to_hi().until(primary_span)) 597 { 598 // We are pointing at the binding's type or initializer value, but it's pattern 599 // is in a different line, so we point at both. 600 err.span_label(secondary_span, "expected due to the type of this binding"); 601 err.span_label(primary_span, format!("expected due to this{post_message}")); 602 } else if post_message == "" { 603 // We are pointing at either the assignment lhs or the binding def pattern. 604 err.span_label(primary_span, "expected due to the type of this binding"); 605 } else { 606 // We are pointing at the binding's type or initializer value. 607 err.span_label(primary_span, format!("expected due to this{post_message}")); 608 } 609 610 if !lhs.is_syntactic_place_expr() { 611 // We already emitted E0070 "invalid left-hand side of assignment", so we 612 // silence this. 613 err.downgrade_to_delayed_bug(); 614 } 615 } 616 ( 617 Some(hir::Node::Expr(hir::Expr { 618 kind: hir::ExprKind::Binary(_, lhs, rhs), .. 619 })), 620 Some(TypeError::Sorts(ExpectedFound { expected, .. })), 621 ) if rhs.hir_id == expr.hir_id 622 && self.typeck_results.borrow().expr_ty_adjusted_opt(lhs) == Some(expected) => 623 { 624 err.span_label(lhs.span, format!("expected because this is `{expected}`")); 625 } 626 _ => {} 627 } 628 } 629 annotate_alternative_method_deref( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, error: Option<TypeError<'tcx>>, )630 fn annotate_alternative_method_deref( 631 &self, 632 err: &mut Diagnostic, 633 expr: &hir::Expr<'_>, 634 error: Option<TypeError<'tcx>>, 635 ) { 636 let parent = self.tcx.hir().parent_id(expr.hir_id); 637 let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {return;}; 638 let Some(hir::Node::Expr(hir::Expr { 639 kind: hir::ExprKind::Assign(lhs, rhs, _), .. 640 })) = self.tcx.hir().find(parent) else {return; }; 641 if rhs.hir_id != expr.hir_id || expected.is_closure() { 642 return; 643 } 644 let hir::ExprKind::Unary(hir::UnOp::Deref, deref) = lhs.kind else { return; }; 645 let hir::ExprKind::MethodCall(path, base, args, _) = deref.kind else { return; }; 646 let Some(self_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(base) else { return; }; 647 648 let Ok(pick) = self 649 .lookup_probe_for_diagnostic( 650 path.ident, 651 self_ty, 652 deref, 653 probe::ProbeScope::TraitsInScope, 654 None, 655 ) else { 656 return; 657 }; 658 let in_scope_methods = self.probe_for_name_many( 659 probe::Mode::MethodCall, 660 path.ident, 661 Some(expected), 662 probe::IsSuggestion(true), 663 self_ty, 664 deref.hir_id, 665 probe::ProbeScope::TraitsInScope, 666 ); 667 let other_methods_in_scope: Vec<_> = 668 in_scope_methods.iter().filter(|c| c.item.def_id != pick.item.def_id).collect(); 669 670 let all_methods = self.probe_for_name_many( 671 probe::Mode::MethodCall, 672 path.ident, 673 Some(expected), 674 probe::IsSuggestion(true), 675 self_ty, 676 deref.hir_id, 677 probe::ProbeScope::AllTraits, 678 ); 679 let suggestions: Vec<_> = all_methods 680 .into_iter() 681 .filter(|c| c.item.def_id != pick.item.def_id) 682 .map(|c| { 683 let m = c.item; 684 let substs = ty::InternalSubsts::for_item(self.tcx, m.def_id, |param, _| { 685 self.var_for_def(deref.span, param) 686 }); 687 let mutability = 688 match self.tcx.fn_sig(m.def_id).skip_binder().input(0).skip_binder().kind() { 689 ty::Ref(_, _, hir::Mutability::Mut) => "&mut ", 690 ty::Ref(_, _, _) => "&", 691 _ => "", 692 }; 693 vec![ 694 ( 695 deref.span.until(base.span), 696 format!( 697 "{}({}", 698 with_no_trimmed_paths!( 699 self.tcx.def_path_str_with_substs(m.def_id, substs,) 700 ), 701 mutability, 702 ), 703 ), 704 match &args[..] { 705 [] => (base.span.shrink_to_hi().with_hi(deref.span.hi()), ")".to_string()), 706 [first, ..] => (base.span.between(first.span), ", ".to_string()), 707 }, 708 ] 709 }) 710 .collect(); 711 if suggestions.is_empty() { 712 return; 713 } 714 let mut path_span: MultiSpan = path.ident.span.into(); 715 path_span.push_span_label( 716 path.ident.span, 717 with_no_trimmed_paths!(format!( 718 "refers to `{}`", 719 self.tcx.def_path_str(pick.item.def_id), 720 )), 721 ); 722 let container_id = pick.item.container_id(self.tcx); 723 let container = with_no_trimmed_paths!(self.tcx.def_path_str(container_id)); 724 for def_id in pick.import_ids { 725 let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); 726 path_span.push_span_label( 727 self.tcx.hir().span(hir_id), 728 format!("`{container}` imported here"), 729 ); 730 } 731 let tail = with_no_trimmed_paths!(match &other_methods_in_scope[..] { 732 [] => return, 733 [candidate] => format!( 734 "the method of the same name on {} `{}`", 735 match candidate.kind { 736 probe::CandidateKind::InherentImplCandidate(..) => "the inherent impl for", 737 _ => "trait", 738 }, 739 self.tcx.def_path_str(candidate.item.container_id(self.tcx)) 740 ), 741 [.., last] if other_methods_in_scope.len() < 5 => { 742 format!( 743 "the methods of the same name on {} and `{}`", 744 other_methods_in_scope[..other_methods_in_scope.len() - 1] 745 .iter() 746 .map(|c| format!( 747 "`{}`", 748 self.tcx.def_path_str(c.item.container_id(self.tcx)) 749 )) 750 .collect::<Vec<String>>() 751 .join(", "), 752 self.tcx.def_path_str(last.item.container_id(self.tcx)) 753 ) 754 } 755 _ => format!( 756 "the methods of the same name on {} other traits", 757 other_methods_in_scope.len() 758 ), 759 }); 760 err.span_note( 761 path_span, 762 format!( 763 "the `{}` call is resolved to the method in `{container}`, shadowing {tail}", 764 path.ident, 765 ), 766 ); 767 if suggestions.len() > other_methods_in_scope.len() { 768 err.note(format!( 769 "additionally, there are {} other available methods that aren't in scope", 770 suggestions.len() - other_methods_in_scope.len() 771 )); 772 } 773 err.multipart_suggestions( 774 format!( 775 "you might have meant to call {}; you can use the fully-qualified path to call {} \ 776 explicitly", 777 if suggestions.len() == 1 { 778 "the other method" 779 } else { 780 "one of the other methods" 781 }, 782 if suggestions.len() == 1 { "it" } else { "one of them" }, 783 ), 784 suggestions, 785 Applicability::MaybeIncorrect, 786 ); 787 } 788 suggest_coercing_result_via_try_operator( &self, err: &mut Diagnostic, expr: &hir::Expr<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, ) -> bool789 pub(crate) fn suggest_coercing_result_via_try_operator( 790 &self, 791 err: &mut Diagnostic, 792 expr: &hir::Expr<'tcx>, 793 expected: Ty<'tcx>, 794 found: Ty<'tcx>, 795 ) -> bool { 796 let ty::Adt(e, substs_e) = expected.kind() else { return false; }; 797 let ty::Adt(f, substs_f) = found.kind() else { return false; }; 798 if e.did() != f.did() { 799 return false; 800 } 801 if Some(e.did()) != self.tcx.get_diagnostic_item(sym::Result) { 802 return false; 803 } 804 let map = self.tcx.hir(); 805 if let Some(hir::Node::Expr(expr)) = map.find_parent(expr.hir_id) 806 && let hir::ExprKind::Ret(_) = expr.kind 807 { 808 // `return foo;` 809 } else if map.get_return_block(expr.hir_id).is_some() { 810 // Function's tail expression. 811 } else { 812 return false; 813 } 814 let e = substs_e.type_at(1); 815 let f = substs_f.type_at(1); 816 if self 817 .infcx 818 .type_implements_trait( 819 self.tcx.get_diagnostic_item(sym::Into).unwrap(), 820 [f, e], 821 self.param_env, 822 ) 823 .must_apply_modulo_regions() 824 { 825 err.multipart_suggestion( 826 "use `?` to coerce and return an appropriate `Err`, and wrap the resulting value \ 827 in `Ok` so the expression remains of type `Result`", 828 vec![ 829 (expr.span.shrink_to_lo(), "Ok(".to_string()), 830 (expr.span.shrink_to_hi(), "?)".to_string()), 831 ], 832 Applicability::MaybeIncorrect, 833 ); 834 return true; 835 } 836 false 837 } 838 839 /// If the expected type is an enum (Issue #55250) with any variants whose 840 /// sole field is of the found type, suggest such variants. (Issue #42764) suggest_compatible_variants( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, expected: Ty<'tcx>, expr_ty: Ty<'tcx>, ) -> bool841 fn suggest_compatible_variants( 842 &self, 843 err: &mut Diagnostic, 844 expr: &hir::Expr<'_>, 845 expected: Ty<'tcx>, 846 expr_ty: Ty<'tcx>, 847 ) -> bool { 848 if let ty::Adt(expected_adt, substs) = expected.kind() { 849 if let hir::ExprKind::Field(base, ident) = expr.kind { 850 let base_ty = self.typeck_results.borrow().expr_ty(base); 851 if self.can_eq(self.param_env, base_ty, expected) 852 && let Some(base_span) = base.span.find_ancestor_inside(expr.span) 853 { 854 err.span_suggestion_verbose( 855 expr.span.with_lo(base_span.hi()), 856 format!("consider removing the tuple struct field `{ident}`"), 857 "", 858 Applicability::MaybeIncorrect, 859 ); 860 return true; 861 } 862 } 863 864 // If the expression is of type () and it's the return expression of a block, 865 // we suggest adding a separate return expression instead. 866 // (To avoid things like suggesting `Ok(while .. { .. })`.) 867 if expr_ty.is_unit() { 868 let mut id = expr.hir_id; 869 let mut parent; 870 871 // Unroll desugaring, to make sure this works for `for` loops etc. 872 loop { 873 parent = self.tcx.hir().parent_id(id); 874 if let Some(parent_span) = self.tcx.hir().opt_span(parent) { 875 if parent_span.find_ancestor_inside(expr.span).is_some() { 876 // The parent node is part of the same span, so is the result of the 877 // same expansion/desugaring and not the 'real' parent node. 878 id = parent; 879 continue; 880 } 881 } 882 break; 883 } 884 885 if let Some(hir::Node::Block(&hir::Block { 886 span: block_span, expr: Some(e), .. 887 })) = self.tcx.hir().find(parent) 888 { 889 if e.hir_id == id { 890 if let Some(span) = expr.span.find_ancestor_inside(block_span) { 891 let return_suggestions = if self 892 .tcx 893 .is_diagnostic_item(sym::Result, expected_adt.did()) 894 { 895 vec!["Ok(())"] 896 } else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) { 897 vec!["None", "Some(())"] 898 } else { 899 return false; 900 }; 901 if let Some(indent) = 902 self.tcx.sess.source_map().indentation_before(span.shrink_to_lo()) 903 { 904 // Add a semicolon, except after `}`. 905 let semicolon = 906 match self.tcx.sess.source_map().span_to_snippet(span) { 907 Ok(s) if s.ends_with('}') => "", 908 _ => ";", 909 }; 910 err.span_suggestions( 911 span.shrink_to_hi(), 912 "try adding an expression at the end of the block", 913 return_suggestions 914 .into_iter() 915 .map(|r| format!("{semicolon}\n{indent}{r}")), 916 Applicability::MaybeIncorrect, 917 ); 918 } 919 return true; 920 } 921 } 922 } 923 } 924 925 let compatible_variants: Vec<(String, _, _, Option<String>)> = expected_adt 926 .variants() 927 .iter() 928 .filter(|variant| { 929 variant.fields.len() == 1 930 }) 931 .filter_map(|variant| { 932 let sole_field = &variant.single_field(); 933 934 let field_is_local = sole_field.did.is_local(); 935 let field_is_accessible = 936 sole_field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx) 937 // Skip suggestions for unstable public fields (for example `Pin::pointer`) 938 && matches!(self.tcx.eval_stability(sole_field.did, None, expr.span, None), EvalResult::Allow | EvalResult::Unmarked); 939 940 if !field_is_local && !field_is_accessible { 941 return None; 942 } 943 944 let note_about_variant_field_privacy = (field_is_local && !field_is_accessible) 945 .then(|| " (its field is private, but it's local to this crate and its privacy can be changed)".to_string()); 946 947 let sole_field_ty = sole_field.ty(self.tcx, substs); 948 if self.can_coerce(expr_ty, sole_field_ty) { 949 let variant_path = 950 with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id)); 951 // FIXME #56861: DRYer prelude filtering 952 if let Some(path) = variant_path.strip_prefix("std::prelude::") 953 && let Some((_, path)) = path.split_once("::") 954 { 955 return Some((path.to_string(), variant.ctor_kind(), sole_field.name, note_about_variant_field_privacy)); 956 } 957 Some((variant_path, variant.ctor_kind(), sole_field.name, note_about_variant_field_privacy)) 958 } else { 959 None 960 } 961 }) 962 .collect(); 963 964 let suggestions_for = |variant: &_, ctor_kind, field_name| { 965 let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) { 966 Some(ident) => format!("{ident}: "), 967 None => String::new(), 968 }; 969 970 let (open, close) = match ctor_kind { 971 Some(CtorKind::Fn) => ("(".to_owned(), ")"), 972 None => (format!(" {{ {field_name}: "), " }"), 973 974 // unit variants don't have fields 975 Some(CtorKind::Const) => unreachable!(), 976 }; 977 978 // Suggest constructor as deep into the block tree as possible. 979 // This fixes https://github.com/rust-lang/rust/issues/101065, 980 // and also just helps make the most minimal suggestions. 981 let mut expr = expr; 982 while let hir::ExprKind::Block(block, _) = &expr.kind 983 && let Some(expr_) = &block.expr 984 { 985 expr = expr_ 986 } 987 988 vec![ 989 (expr.span.shrink_to_lo(), format!("{prefix}{variant}{open}")), 990 (expr.span.shrink_to_hi(), close.to_owned()), 991 ] 992 }; 993 994 match &compatible_variants[..] { 995 [] => { /* No variants to format */ } 996 [(variant, ctor_kind, field_name, note)] => { 997 // Just a single matching variant. 998 err.multipart_suggestion_verbose( 999 format!( 1000 "try wrapping the expression in `{variant}`{note}", 1001 note = note.as_deref().unwrap_or("") 1002 ), 1003 suggestions_for(&**variant, *ctor_kind, *field_name), 1004 Applicability::MaybeIncorrect, 1005 ); 1006 return true; 1007 } 1008 _ => { 1009 // More than one matching variant. 1010 err.multipart_suggestions( 1011 format!( 1012 "try wrapping the expression in a variant of `{}`", 1013 self.tcx.def_path_str(expected_adt.did()) 1014 ), 1015 compatible_variants.into_iter().map( 1016 |(variant, ctor_kind, field_name, _)| { 1017 suggestions_for(&variant, ctor_kind, field_name) 1018 }, 1019 ), 1020 Applicability::MaybeIncorrect, 1021 ); 1022 return true; 1023 } 1024 } 1025 } 1026 1027 false 1028 } 1029 suggest_non_zero_new_unwrap( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, expected: Ty<'tcx>, expr_ty: Ty<'tcx>, ) -> bool1030 fn suggest_non_zero_new_unwrap( 1031 &self, 1032 err: &mut Diagnostic, 1033 expr: &hir::Expr<'_>, 1034 expected: Ty<'tcx>, 1035 expr_ty: Ty<'tcx>, 1036 ) -> bool { 1037 let tcx = self.tcx; 1038 let (adt, unwrap) = match expected.kind() { 1039 // In case Option<NonZero*> is wanted, but * is provided, suggest calling new 1040 ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => { 1041 // Unwrap option 1042 let ty::Adt(adt, _) = substs.type_at(0).kind() else { return false; }; 1043 1044 (adt, "") 1045 } 1046 // In case NonZero* is wanted, but * is provided also add `.unwrap()` to satisfy types 1047 ty::Adt(adt, _) => (adt, ".unwrap()"), 1048 _ => return false, 1049 }; 1050 1051 let map = [ 1052 (sym::NonZeroU8, tcx.types.u8), 1053 (sym::NonZeroU16, tcx.types.u16), 1054 (sym::NonZeroU32, tcx.types.u32), 1055 (sym::NonZeroU64, tcx.types.u64), 1056 (sym::NonZeroU128, tcx.types.u128), 1057 (sym::NonZeroI8, tcx.types.i8), 1058 (sym::NonZeroI16, tcx.types.i16), 1059 (sym::NonZeroI32, tcx.types.i32), 1060 (sym::NonZeroI64, tcx.types.i64), 1061 (sym::NonZeroI128, tcx.types.i128), 1062 ]; 1063 1064 let Some((s, _)) = map 1065 .iter() 1066 .find(|&&(s, t)| self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t)) 1067 else { return false; }; 1068 1069 let path = self.tcx.def_path_str(adt.non_enum_variant().def_id); 1070 1071 err.multipart_suggestion( 1072 format!("consider calling `{s}::new`"), 1073 vec![ 1074 (expr.span.shrink_to_lo(), format!("{path}::new(")), 1075 (expr.span.shrink_to_hi(), format!("){unwrap}")), 1076 ], 1077 Applicability::MaybeIncorrect, 1078 ); 1079 1080 true 1081 } 1082 get_conversion_methods( &self, span: Span, expected: Ty<'tcx>, checked_ty: Ty<'tcx>, hir_id: hir::HirId, ) -> Vec<AssocItem>1083 pub fn get_conversion_methods( 1084 &self, 1085 span: Span, 1086 expected: Ty<'tcx>, 1087 checked_ty: Ty<'tcx>, 1088 hir_id: hir::HirId, 1089 ) -> Vec<AssocItem> { 1090 let methods = self.probe_for_return_type( 1091 span, 1092 probe::Mode::MethodCall, 1093 expected, 1094 checked_ty, 1095 hir_id, 1096 |m| { 1097 self.has_only_self_parameter(m) 1098 && self 1099 .tcx 1100 // This special internal attribute is used to permit 1101 // "identity-like" conversion methods to be suggested here. 1102 // 1103 // FIXME (#46459 and #46460): ideally 1104 // `std::convert::Into::into` and `std::borrow:ToOwned` would 1105 // also be `#[rustc_conversion_suggestion]`, if not for 1106 // method-probing false-positives and -negatives (respectively). 1107 // 1108 // FIXME? Other potential candidate methods: `as_ref` and 1109 // `as_mut`? 1110 .has_attr(m.def_id, sym::rustc_conversion_suggestion) 1111 }, 1112 ); 1113 1114 methods 1115 } 1116 1117 /// This function checks whether the method is not static and does not accept other parameters than `self`. has_only_self_parameter(&self, method: &AssocItem) -> bool1118 fn has_only_self_parameter(&self, method: &AssocItem) -> bool { 1119 match method.kind { 1120 ty::AssocKind::Fn => { 1121 method.fn_has_self_parameter 1122 && self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len() 1123 == 1 1124 } 1125 _ => false, 1126 } 1127 } 1128 1129 /// Identify some cases where `as_ref()` would be appropriate and suggest it. 1130 /// 1131 /// Given the following code: 1132 /// ```compile_fail,E0308 1133 /// struct Foo; 1134 /// fn takes_ref(_: &Foo) {} 1135 /// let ref opt = Some(Foo); 1136 /// 1137 /// opt.map(|param| takes_ref(param)); 1138 /// ``` 1139 /// Suggest using `opt.as_ref().map(|param| takes_ref(param));` instead. 1140 /// 1141 /// It only checks for `Option` and `Result` and won't work with 1142 /// ```ignore (illustrative) 1143 /// opt.map(|param| { takes_ref(param) }); 1144 /// ``` can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Vec<(Span, String)>, &'static str)>1145 fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Vec<(Span, String)>, &'static str)> { 1146 let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind else { 1147 return None; 1148 }; 1149 1150 let hir::def::Res::Local(local_id) = path.res else { 1151 return None; 1152 }; 1153 1154 let local_parent = self.tcx.hir().parent_id(local_id); 1155 let Some(Node::Param(hir::Param { hir_id: param_hir_id, .. })) = self.tcx.hir().find(local_parent) else { 1156 return None; 1157 }; 1158 1159 let param_parent = self.tcx.hir().parent_id(*param_hir_id); 1160 let Some(Node::Expr(hir::Expr { 1161 hir_id: expr_hir_id, 1162 kind: hir::ExprKind::Closure(hir::Closure { fn_decl: closure_fn_decl, .. }), 1163 .. 1164 })) = self.tcx.hir().find(param_parent) else { 1165 return None; 1166 }; 1167 1168 let expr_parent = self.tcx.hir().parent_id(*expr_hir_id); 1169 let hir = self.tcx.hir().find(expr_parent); 1170 let closure_params_len = closure_fn_decl.inputs.len(); 1171 let ( 1172 Some(Node::Expr(hir::Expr { 1173 kind: hir::ExprKind::MethodCall(method_path, receiver, ..), 1174 .. 1175 })), 1176 1, 1177 ) = (hir, closure_params_len) else { 1178 return None; 1179 }; 1180 1181 let self_ty = self.typeck_results.borrow().expr_ty(receiver); 1182 let name = method_path.ident.name; 1183 let is_as_ref_able = match self_ty.peel_refs().kind() { 1184 ty::Adt(def, _) => { 1185 (self.tcx.is_diagnostic_item(sym::Option, def.did()) 1186 || self.tcx.is_diagnostic_item(sym::Result, def.did())) 1187 && (name == sym::map || name == sym::and_then) 1188 } 1189 _ => false, 1190 }; 1191 if is_as_ref_able { 1192 Some(( 1193 vec![(method_path.ident.span.shrink_to_lo(), "as_ref().".to_string())], 1194 "consider using `as_ref` instead", 1195 )) 1196 } else { 1197 None 1198 } 1199 } 1200 maybe_get_struct_pattern_shorthand_field( &self, expr: &hir::Expr<'_>, ) -> Option<Symbol>1201 pub(crate) fn maybe_get_struct_pattern_shorthand_field( 1202 &self, 1203 expr: &hir::Expr<'_>, 1204 ) -> Option<Symbol> { 1205 let hir = self.tcx.hir(); 1206 let local = match expr { 1207 hir::Expr { 1208 kind: 1209 hir::ExprKind::Path(hir::QPath::Resolved( 1210 None, 1211 hir::Path { 1212 res: hir::def::Res::Local(_), 1213 segments: [hir::PathSegment { ident, .. }], 1214 .. 1215 }, 1216 )), 1217 .. 1218 } => Some(ident), 1219 _ => None, 1220 }?; 1221 1222 match hir.find_parent(expr.hir_id)? { 1223 Node::ExprField(field) => { 1224 if field.ident.name == local.name && field.is_shorthand { 1225 return Some(local.name); 1226 } 1227 } 1228 _ => {} 1229 } 1230 1231 None 1232 } 1233 1234 /// If the given `HirId` corresponds to a block with a trailing expression, return that expression maybe_get_block_expr( &self, expr: &hir::Expr<'tcx>, ) -> Option<&'tcx hir::Expr<'tcx>>1235 pub(crate) fn maybe_get_block_expr( 1236 &self, 1237 expr: &hir::Expr<'tcx>, 1238 ) -> Option<&'tcx hir::Expr<'tcx>> { 1239 match expr { 1240 hir::Expr { kind: hir::ExprKind::Block(block, ..), .. } => block.expr, 1241 _ => None, 1242 } 1243 } 1244 1245 /// Returns whether the given expression is an `else if`. is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool1246 pub(crate) fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool { 1247 if let hir::ExprKind::If(..) = expr.kind { 1248 let parent_id = self.tcx.hir().parent_id(expr.hir_id); 1249 if let Some(Node::Expr(hir::Expr { 1250 kind: hir::ExprKind::If(_, _, Some(else_expr)), 1251 .. 1252 })) = self.tcx.hir().find(parent_id) 1253 { 1254 return else_expr.hir_id == expr.hir_id; 1255 } 1256 } 1257 false 1258 } 1259 1260 // Returns whether the given expression is a destruct assignment desugaring. 1261 // For example, `(a, b) = (1, &2);` 1262 // Here we try to find the pattern binding of the expression, 1263 // `default_binding_modes` is false only for destruct assignment desugaring. is_destruct_assignment_desugaring(&self, expr: &hir::Expr<'_>) -> bool1264 pub(crate) fn is_destruct_assignment_desugaring(&self, expr: &hir::Expr<'_>) -> bool { 1265 if let hir::ExprKind::Path(hir::QPath::Resolved( 1266 _, 1267 hir::Path { res: hir::def::Res::Local(bind_hir_id), .. }, 1268 )) = expr.kind 1269 { 1270 let bind = self.tcx.hir().find(*bind_hir_id); 1271 let parent = self.tcx.hir().find(self.tcx.hir().parent_id(*bind_hir_id)); 1272 if let Some(hir::Node::Pat(hir::Pat { kind: hir::PatKind::Binding(_, _hir_id, _, _), .. })) = bind && 1273 let Some(hir::Node::Pat(hir::Pat { default_binding_modes: false, .. })) = parent { 1274 return true; 1275 } 1276 } 1277 return false; 1278 } 1279 1280 /// This function is used to determine potential "simple" improvements or users' errors and 1281 /// provide them useful help. For example: 1282 /// 1283 /// ```compile_fail,E0308 1284 /// fn some_fn(s: &str) {} 1285 /// 1286 /// let x = "hey!".to_owned(); 1287 /// some_fn(x); // error 1288 /// ``` 1289 /// 1290 /// No need to find every potential function which could make a coercion to transform a 1291 /// `String` into a `&str` since a `&` would do the trick! 1292 /// 1293 /// In addition of this check, it also checks between references mutability state. If the 1294 /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with 1295 /// `&mut`!". suggest_deref_or_ref( &self, expr: &hir::Expr<'tcx>, checked_ty: Ty<'tcx>, expected: Ty<'tcx>, ) -> Option<( Vec<(Span, String)>, String, Applicability, bool, bool, )>1296 pub fn suggest_deref_or_ref( 1297 &self, 1298 expr: &hir::Expr<'tcx>, 1299 checked_ty: Ty<'tcx>, 1300 expected: Ty<'tcx>, 1301 ) -> Option<( 1302 Vec<(Span, String)>, 1303 String, 1304 Applicability, 1305 bool, /* verbose */ 1306 bool, /* suggest `&` or `&mut` type annotation */ 1307 )> { 1308 let sess = self.sess(); 1309 let sp = expr.span; 1310 1311 // If the span is from an external macro, there's no suggestion we can make. 1312 if in_external_macro(sess, sp) { 1313 return None; 1314 } 1315 1316 let sm = sess.source_map(); 1317 1318 let replace_prefix = |s: &str, old: &str, new: &str| { 1319 s.strip_prefix(old).map(|stripped| new.to_string() + stripped) 1320 }; 1321 1322 // `ExprKind::DropTemps` is semantically irrelevant for these suggestions. 1323 let expr = expr.peel_drop_temps(); 1324 1325 match (&expr.kind, expected.kind(), checked_ty.kind()) { 1326 (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (exp.kind(), check.kind()) { 1327 (&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => { 1328 if let hir::ExprKind::Lit(_) = expr.kind 1329 && let Ok(src) = sm.span_to_snippet(sp) 1330 && replace_prefix(&src, "b\"", "\"").is_some() 1331 { 1332 let pos = sp.lo() + BytePos(1); 1333 return Some(( 1334 vec![(sp.with_hi(pos), String::new())], 1335 "consider removing the leading `b`".to_string(), 1336 Applicability::MachineApplicable, 1337 true, 1338 false, 1339 )); 1340 } 1341 } 1342 (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => { 1343 if let hir::ExprKind::Lit(_) = expr.kind 1344 && let Ok(src) = sm.span_to_snippet(sp) 1345 && replace_prefix(&src, "\"", "b\"").is_some() 1346 { 1347 return Some(( 1348 vec![(sp.shrink_to_lo(), "b".to_string())], 1349 "consider adding a leading `b`".to_string(), 1350 Applicability::MachineApplicable, 1351 true, 1352 false, 1353 )); 1354 } 1355 } 1356 _ => {} 1357 }, 1358 (_, &ty::Ref(_, _, mutability), _) => { 1359 // Check if it can work when put into a ref. For example: 1360 // 1361 // ``` 1362 // fn bar(x: &mut i32) {} 1363 // 1364 // let x = 0u32; 1365 // bar(&x); // error, expected &mut 1366 // ``` 1367 let ref_ty = match mutability { 1368 hir::Mutability::Mut => { 1369 Ty::new_mut_ref(self.tcx,self.tcx.lifetimes.re_static, checked_ty) 1370 } 1371 hir::Mutability::Not => { 1372 Ty::new_imm_ref(self.tcx,self.tcx.lifetimes.re_static, checked_ty) 1373 } 1374 }; 1375 if self.can_coerce(ref_ty, expected) { 1376 let mut sugg_sp = sp; 1377 if let hir::ExprKind::MethodCall(ref segment, receiver, args, _) = expr.kind { 1378 let clone_trait = 1379 self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span)); 1380 if args.is_empty() 1381 && self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map( 1382 |did| { 1383 let ai = self.tcx.associated_item(did); 1384 ai.trait_container(self.tcx) == Some(clone_trait) 1385 }, 1386 ) == Some(true) 1387 && segment.ident.name == sym::clone 1388 { 1389 // If this expression had a clone call when suggesting borrowing 1390 // we want to suggest removing it because it'd now be unnecessary. 1391 sugg_sp = receiver.span; 1392 } 1393 } 1394 1395 if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner) = expr.kind 1396 && let Some(1) = self.deref_steps(expected, checked_ty) 1397 { 1398 // We have `*&T`, check if what was expected was `&T`. 1399 // If so, we may want to suggest removing a `*`. 1400 sugg_sp = sugg_sp.with_hi(inner.span.lo()); 1401 return Some(( 1402 vec![(sugg_sp, String::new())], 1403 "consider removing deref here".to_string(), 1404 Applicability::MachineApplicable, 1405 true, 1406 false, 1407 )); 1408 } 1409 1410 let needs_parens = match expr.kind { 1411 // parenthesize if needed (Issue #46756) 1412 hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, 1413 // parenthesize borrows of range literals (Issue #54505) 1414 _ if is_range_literal(expr) => true, 1415 _ => false, 1416 }; 1417 1418 if let Some((sugg, msg)) = self.can_use_as_ref(expr) { 1419 return Some(( 1420 sugg, 1421 msg.to_string(), 1422 Applicability::MachineApplicable, 1423 true, 1424 false, 1425 )); 1426 } 1427 1428 let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) { 1429 Some(ident) => format!("{ident}: "), 1430 None => String::new(), 1431 }; 1432 1433 if let Some(hir::Node::Expr(hir::Expr { 1434 kind: hir::ExprKind::Assign(..), 1435 .. 1436 })) = self.tcx.hir().find_parent(expr.hir_id) 1437 { 1438 if mutability.is_mut() { 1439 // Suppressing this diagnostic, we'll properly print it in `check_expr_assign` 1440 return None; 1441 } 1442 } 1443 1444 let sugg = mutability.ref_prefix_str(); 1445 let (sugg, verbose) = if needs_parens { 1446 ( 1447 vec![ 1448 (sp.shrink_to_lo(), format!("{prefix}{sugg}(")), 1449 (sp.shrink_to_hi(), ")".to_string()), 1450 ], 1451 false, 1452 ) 1453 } else { 1454 (vec![(sp.shrink_to_lo(), format!("{prefix}{sugg}"))], true) 1455 }; 1456 return Some(( 1457 sugg, 1458 format!("consider {}borrowing here", mutability.mutably_str()), 1459 Applicability::MachineApplicable, 1460 verbose, 1461 false, 1462 )); 1463 } 1464 } 1465 ( 1466 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr), 1467 _, 1468 &ty::Ref(_, checked, _), 1469 ) if self.can_sub(self.param_env, checked, expected) => { 1470 let make_sugg = |start: Span, end: BytePos| { 1471 // skip `(` for tuples such as `(c) = (&123)`. 1472 // make sure we won't suggest like `(c) = 123)` which is incorrect. 1473 let sp = sm.span_extend_while(start.shrink_to_lo(), |c| c == '(' || c.is_whitespace()) 1474 .map_or(start, |s| s.shrink_to_hi()); 1475 Some(( 1476 vec![(sp.with_hi(end), String::new())], 1477 "consider removing the borrow".to_string(), 1478 Applicability::MachineApplicable, 1479 true, 1480 true, 1481 )) 1482 }; 1483 1484 // We have `&T`, check if what was expected was `T`. If so, 1485 // we may want to suggest removing a `&`. 1486 if sm.is_imported(expr.span) { 1487 // Go through the spans from which this span was expanded, 1488 // and find the one that's pointing inside `sp`. 1489 // 1490 // E.g. for `&format!("")`, where we want the span to the 1491 // `format!()` invocation instead of its expansion. 1492 if let Some(call_span) = 1493 iter::successors(Some(expr.span), |s| s.parent_callsite()) 1494 .find(|&s| sp.contains(s)) 1495 && sm.is_span_accessible(call_span) 1496 { 1497 return make_sugg(sp, call_span.lo()) 1498 } 1499 return None; 1500 } 1501 if sp.contains(expr.span) && sm.is_span_accessible(expr.span) { 1502 return make_sugg(sp, expr.span.lo()) 1503 } 1504 } 1505 ( 1506 _, 1507 &ty::RawPtr(TypeAndMut { ty: ty_b, mutbl: mutbl_b }), 1508 &ty::Ref(_, ty_a, mutbl_a), 1509 ) => { 1510 if let Some(steps) = self.deref_steps(ty_a, ty_b) 1511 // Only suggest valid if dereferencing needed. 1512 && steps > 0 1513 // The pointer type implements `Copy` trait so the suggestion is always valid. 1514 && let Ok(src) = sm.span_to_snippet(sp) 1515 { 1516 let derefs = "*".repeat(steps); 1517 let old_prefix = mutbl_a.ref_prefix_str(); 1518 let new_prefix = mutbl_b.ref_prefix_str().to_owned() + &derefs; 1519 1520 let suggestion = replace_prefix(&src, old_prefix, &new_prefix).map(|_| { 1521 // skip `&` or `&mut ` if both mutabilities are mutable 1522 let lo = sp.lo() 1523 + BytePos(min(old_prefix.len(), mutbl_b.ref_prefix_str().len()) as _); 1524 // skip `&` or `&mut ` 1525 let hi = sp.lo() + BytePos(old_prefix.len() as _); 1526 let sp = sp.with_lo(lo).with_hi(hi); 1527 1528 ( 1529 sp, 1530 format!( 1531 "{}{derefs}", 1532 if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" } 1533 ), 1534 if mutbl_b <= mutbl_a { 1535 Applicability::MachineApplicable 1536 } else { 1537 Applicability::MaybeIncorrect 1538 }, 1539 ) 1540 }); 1541 1542 if let Some((span, src, applicability)) = suggestion { 1543 return Some(( 1544 vec![(span, src)], 1545 "consider dereferencing".to_string(), 1546 applicability, 1547 true, 1548 false, 1549 )); 1550 } 1551 } 1552 } 1553 _ if sp == expr.span => { 1554 if let Some(mut steps) = self.deref_steps(checked_ty, expected) { 1555 let mut expr = expr.peel_blocks(); 1556 let mut prefix_span = expr.span.shrink_to_lo(); 1557 let mut remove = String::new(); 1558 1559 // Try peeling off any existing `&` and `&mut` to reach our target type 1560 while steps > 0 { 1561 if let hir::ExprKind::AddrOf(_, mutbl, inner) = expr.kind { 1562 // If the expression has `&`, removing it would fix the error 1563 prefix_span = prefix_span.with_hi(inner.span.lo()); 1564 expr = inner; 1565 remove.push_str(mutbl.ref_prefix_str()); 1566 steps -= 1; 1567 } else { 1568 break; 1569 } 1570 } 1571 // If we've reached our target type with just removing `&`, then just print now. 1572 if steps == 0 && !remove.trim().is_empty() { 1573 return Some(( 1574 vec![(prefix_span, String::new())], 1575 format!("consider removing the `{}`", remove.trim()), 1576 // Do not remove `&&` to get to bool, because it might be something like 1577 // { a } && b, which we have a separate fixup suggestion that is more 1578 // likely correct... 1579 if remove.trim() == "&&" && expected == self.tcx.types.bool { 1580 Applicability::MaybeIncorrect 1581 } else { 1582 Applicability::MachineApplicable 1583 }, 1584 true, 1585 false, 1586 )); 1587 } 1588 1589 // For this suggestion to make sense, the type would need to be `Copy`, 1590 // or we have to be moving out of a `Box<T>` 1591 if self.type_is_copy_modulo_regions(self.param_env, expected) 1592 // FIXME(compiler-errors): We can actually do this if the checked_ty is 1593 // `steps` layers of boxes, not just one, but this is easier and most likely. 1594 || (checked_ty.is_box() && steps == 1) 1595 // We can always deref a binop that takes its arguments by ref. 1596 || matches!( 1597 self.tcx.hir().get_parent(expr.hir_id), 1598 hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, ..), .. }) 1599 if !op.node.is_by_value() 1600 ) 1601 { 1602 let deref_kind = if checked_ty.is_box() { 1603 "unboxing the value" 1604 } else if checked_ty.is_ref() { 1605 "dereferencing the borrow" 1606 } else { 1607 "dereferencing the type" 1608 }; 1609 1610 // Suggest removing `&` if we have removed any, otherwise suggest just 1611 // dereferencing the remaining number of steps. 1612 let message = if remove.is_empty() { 1613 format!("consider {deref_kind}") 1614 } else { 1615 format!( 1616 "consider removing the `{}` and {} instead", 1617 remove.trim(), 1618 deref_kind 1619 ) 1620 }; 1621 1622 let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) { 1623 Some(ident) => format!("{ident}: "), 1624 None => String::new(), 1625 }; 1626 1627 let (span, suggestion) = if self.is_else_if_block(expr) { 1628 // Don't suggest nonsense like `else *if` 1629 return None; 1630 } else if let Some(expr) = self.maybe_get_block_expr(expr) { 1631 // prefix should be empty here.. 1632 (expr.span.shrink_to_lo(), "*".to_string()) 1633 } else { 1634 (prefix_span, format!("{}{}", prefix, "*".repeat(steps))) 1635 }; 1636 if suggestion.trim().is_empty() { 1637 return None; 1638 } 1639 1640 return Some(( 1641 vec![(span, suggestion)], 1642 message, 1643 Applicability::MachineApplicable, 1644 true, 1645 false, 1646 )); 1647 } 1648 } 1649 } 1650 _ => {} 1651 } 1652 None 1653 } 1654 suggest_cast( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, ) -> bool1655 pub fn suggest_cast( 1656 &self, 1657 err: &mut Diagnostic, 1658 expr: &hir::Expr<'_>, 1659 checked_ty: Ty<'tcx>, 1660 expected_ty: Ty<'tcx>, 1661 expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, 1662 ) -> bool { 1663 if self.tcx.sess.source_map().is_imported(expr.span) { 1664 // Ignore if span is from within a macro. 1665 return false; 1666 } 1667 1668 let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) else { 1669 return false; 1670 }; 1671 1672 // If casting this expression to a given numeric type would be appropriate in case of a type 1673 // mismatch. 1674 // 1675 // We want to minimize the amount of casting operations that are suggested, as it can be a 1676 // lossy operation with potentially bad side effects, so we only suggest when encountering 1677 // an expression that indicates that the original type couldn't be directly changed. 1678 // 1679 // For now, don't suggest casting with `as`. 1680 let can_cast = false; 1681 1682 let mut sugg = vec![]; 1683 1684 if let Some(hir::Node::ExprField(field)) = self.tcx.hir().find_parent(expr.hir_id) { 1685 // `expr` is a literal field for a struct, only suggest if appropriate 1686 if field.is_shorthand { 1687 // This is a field literal 1688 sugg.push((field.ident.span.shrink_to_lo(), format!("{}: ", field.ident))); 1689 } else { 1690 // Likely a field was meant, but this field wasn't found. Do not suggest anything. 1691 return false; 1692 } 1693 }; 1694 1695 if let hir::ExprKind::Call(path, args) = &expr.kind 1696 && let (hir::ExprKind::Path(hir::QPath::TypeRelative(base_ty, path_segment)), 1) = 1697 (&path.kind, args.len()) 1698 // `expr` is a conversion like `u32::from(val)`, do not suggest anything (#63697). 1699 && let (hir::TyKind::Path(hir::QPath::Resolved(None, base_ty_path)), sym::from) = 1700 (&base_ty.kind, path_segment.ident.name) 1701 { 1702 if let Some(ident) = &base_ty_path.segments.iter().map(|s| s.ident).next() { 1703 match ident.name { 1704 sym::i128 1705 | sym::i64 1706 | sym::i32 1707 | sym::i16 1708 | sym::i8 1709 | sym::u128 1710 | sym::u64 1711 | sym::u32 1712 | sym::u16 1713 | sym::u8 1714 | sym::isize 1715 | sym::usize 1716 if base_ty_path.segments.len() == 1 => 1717 { 1718 return false; 1719 } 1720 _ => {} 1721 } 1722 } 1723 } 1724 1725 let msg = format!( 1726 "you can convert {} `{}` to {} `{}`", 1727 checked_ty.kind().article(), 1728 checked_ty, 1729 expected_ty.kind().article(), 1730 expected_ty, 1731 ); 1732 let cast_msg = format!( 1733 "you can cast {} `{}` to {} `{}`", 1734 checked_ty.kind().article(), 1735 checked_ty, 1736 expected_ty.kind().article(), 1737 expected_ty, 1738 ); 1739 let lit_msg = format!( 1740 "change the type of the numeric literal from `{checked_ty}` to `{expected_ty}`", 1741 ); 1742 1743 let close_paren = if expr.precedence().order() < PREC_POSTFIX { 1744 sugg.push((expr.span.shrink_to_lo(), "(".to_string())); 1745 ")" 1746 } else { 1747 "" 1748 }; 1749 1750 let mut cast_suggestion = sugg.clone(); 1751 cast_suggestion.push((expr.span.shrink_to_hi(), format!("{close_paren} as {expected_ty}"))); 1752 let mut into_suggestion = sugg.clone(); 1753 into_suggestion.push((expr.span.shrink_to_hi(), format!("{close_paren}.into()"))); 1754 let mut suffix_suggestion = sugg.clone(); 1755 suffix_suggestion.push(( 1756 if matches!( 1757 (&expected_ty.kind(), &checked_ty.kind()), 1758 (ty::Int(_) | ty::Uint(_), ty::Float(_)) 1759 ) { 1760 // Remove fractional part from literal, for example `42.0f32` into `42` 1761 let src = src.trim_end_matches(&checked_ty.to_string()); 1762 let len = src.split('.').next().unwrap().len(); 1763 expr.span.with_lo(expr.span.lo() + BytePos(len as u32)) 1764 } else { 1765 let len = src.trim_end_matches(&checked_ty.to_string()).len(); 1766 expr.span.with_lo(expr.span.lo() + BytePos(len as u32)) 1767 }, 1768 if expr.precedence().order() < PREC_POSTFIX { 1769 // Readd `)` 1770 format!("{expected_ty})") 1771 } else { 1772 expected_ty.to_string() 1773 }, 1774 )); 1775 let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| { 1776 if let hir::ExprKind::Lit(lit) = &expr.kind { lit.node.is_suffixed() } else { false } 1777 }; 1778 let is_negative_int = 1779 |expr: &hir::Expr<'_>| matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::Neg, ..)); 1780 let is_uint = |ty: Ty<'_>| matches!(ty.kind(), ty::Uint(..)); 1781 1782 let in_const_context = self.tcx.hir().is_inside_const_context(expr.hir_id); 1783 1784 let suggest_fallible_into_or_lhs_from = 1785 |err: &mut Diagnostic, exp_to_found_is_fallible: bool| { 1786 // If we know the expression the expected type is derived from, we might be able 1787 // to suggest a widening conversion rather than a narrowing one (which may 1788 // panic). For example, given x: u8 and y: u32, if we know the span of "x", 1789 // x > y 1790 // can be given the suggestion "u32::from(x) > y" rather than 1791 // "x > y.try_into().unwrap()". 1792 let lhs_expr_and_src = expected_ty_expr.and_then(|expr| { 1793 self.tcx 1794 .sess 1795 .source_map() 1796 .span_to_snippet(expr.span) 1797 .ok() 1798 .map(|src| (expr, src)) 1799 }); 1800 let (msg, suggestion) = if let (Some((lhs_expr, lhs_src)), false) = 1801 (lhs_expr_and_src, exp_to_found_is_fallible) 1802 { 1803 let msg = format!( 1804 "you can convert `{lhs_src}` from `{expected_ty}` to `{checked_ty}`, matching the type of `{src}`", 1805 ); 1806 let suggestion = vec![ 1807 (lhs_expr.span.shrink_to_lo(), format!("{checked_ty}::from(")), 1808 (lhs_expr.span.shrink_to_hi(), ")".to_string()), 1809 ]; 1810 (msg, suggestion) 1811 } else { 1812 let msg = 1813 format!("{} and panic if the converted value doesn't fit", msg.clone()); 1814 let mut suggestion = sugg.clone(); 1815 suggestion.push(( 1816 expr.span.shrink_to_hi(), 1817 format!("{close_paren}.try_into().unwrap()"), 1818 )); 1819 (msg, suggestion) 1820 }; 1821 err.multipart_suggestion_verbose(msg, suggestion, Applicability::MachineApplicable); 1822 }; 1823 1824 let suggest_to_change_suffix_or_into = 1825 |err: &mut Diagnostic, 1826 found_to_exp_is_fallible: bool, 1827 exp_to_found_is_fallible: bool| { 1828 let exp_is_lhs = expected_ty_expr.is_some_and(|e| self.tcx.hir().is_lhs(e.hir_id)); 1829 1830 if exp_is_lhs { 1831 return; 1832 } 1833 1834 let always_fallible = found_to_exp_is_fallible 1835 && (exp_to_found_is_fallible || expected_ty_expr.is_none()); 1836 let msg = if literal_is_ty_suffixed(expr) { 1837 lit_msg.clone() 1838 } else if always_fallible && (is_negative_int(expr) && is_uint(expected_ty)) { 1839 // We now know that converting either the lhs or rhs is fallible. Before we 1840 // suggest a fallible conversion, check if the value can never fit in the 1841 // expected type. 1842 let msg = format!("`{src}` cannot fit into type `{expected_ty}`"); 1843 err.note(msg); 1844 return; 1845 } else if in_const_context { 1846 // Do not recommend `into` or `try_into` in const contexts. 1847 return; 1848 } else if found_to_exp_is_fallible { 1849 return suggest_fallible_into_or_lhs_from(err, exp_to_found_is_fallible); 1850 } else { 1851 msg.clone() 1852 }; 1853 let suggestion = if literal_is_ty_suffixed(expr) { 1854 suffix_suggestion.clone() 1855 } else { 1856 into_suggestion.clone() 1857 }; 1858 err.multipart_suggestion_verbose(msg, suggestion, Applicability::MachineApplicable); 1859 }; 1860 1861 match (&expected_ty.kind(), &checked_ty.kind()) { 1862 (ty::Int(exp), ty::Int(found)) => { 1863 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width()) 1864 { 1865 (Some(exp), Some(found)) if exp < found => (true, false), 1866 (Some(exp), Some(found)) if exp > found => (false, true), 1867 (None, Some(8 | 16)) => (false, true), 1868 (Some(8 | 16), None) => (true, false), 1869 (None, _) | (_, None) => (true, true), 1870 _ => (false, false), 1871 }; 1872 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible); 1873 true 1874 } 1875 (ty::Uint(exp), ty::Uint(found)) => { 1876 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width()) 1877 { 1878 (Some(exp), Some(found)) if exp < found => (true, false), 1879 (Some(exp), Some(found)) if exp > found => (false, true), 1880 (None, Some(8 | 16)) => (false, true), 1881 (Some(8 | 16), None) => (true, false), 1882 (None, _) | (_, None) => (true, true), 1883 _ => (false, false), 1884 }; 1885 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible); 1886 true 1887 } 1888 (&ty::Int(exp), &ty::Uint(found)) => { 1889 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width()) 1890 { 1891 (Some(exp), Some(found)) if found < exp => (false, true), 1892 (None, Some(8)) => (false, true), 1893 _ => (true, true), 1894 }; 1895 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible); 1896 true 1897 } 1898 (&ty::Uint(exp), &ty::Int(found)) => { 1899 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width()) 1900 { 1901 (Some(exp), Some(found)) if found > exp => (true, false), 1902 (Some(8), None) => (true, false), 1903 _ => (true, true), 1904 }; 1905 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible); 1906 true 1907 } 1908 (ty::Float(exp), ty::Float(found)) => { 1909 if found.bit_width() < exp.bit_width() { 1910 suggest_to_change_suffix_or_into(err, false, true); 1911 } else if literal_is_ty_suffixed(expr) { 1912 err.multipart_suggestion_verbose( 1913 lit_msg, 1914 suffix_suggestion, 1915 Applicability::MachineApplicable, 1916 ); 1917 } else if can_cast { 1918 // Missing try_into implementation for `f64` to `f32` 1919 err.multipart_suggestion_verbose( 1920 format!("{cast_msg}, producing the closest possible value"), 1921 cast_suggestion, 1922 Applicability::MaybeIncorrect, // lossy conversion 1923 ); 1924 } 1925 true 1926 } 1927 (&ty::Uint(_) | &ty::Int(_), &ty::Float(_)) => { 1928 if literal_is_ty_suffixed(expr) { 1929 err.multipart_suggestion_verbose( 1930 lit_msg, 1931 suffix_suggestion, 1932 Applicability::MachineApplicable, 1933 ); 1934 } else if can_cast { 1935 // Missing try_into implementation for `{float}` to `{integer}` 1936 err.multipart_suggestion_verbose( 1937 format!("{msg}, rounding the float towards zero"), 1938 cast_suggestion, 1939 Applicability::MaybeIncorrect, // lossy conversion 1940 ); 1941 } 1942 true 1943 } 1944 (ty::Float(exp), ty::Uint(found)) => { 1945 // if `found` is `None` (meaning found is `usize`), don't suggest `.into()` 1946 if exp.bit_width() > found.bit_width().unwrap_or(256) { 1947 err.multipart_suggestion_verbose( 1948 format!( 1949 "{msg}, producing the floating point representation of the integer", 1950 ), 1951 into_suggestion, 1952 Applicability::MachineApplicable, 1953 ); 1954 } else if literal_is_ty_suffixed(expr) { 1955 err.multipart_suggestion_verbose( 1956 lit_msg, 1957 suffix_suggestion, 1958 Applicability::MachineApplicable, 1959 ); 1960 } else { 1961 // Missing try_into implementation for `{integer}` to `{float}` 1962 err.multipart_suggestion_verbose( 1963 format!( 1964 "{cast_msg}, producing the floating point representation of the integer, \ 1965 rounded if necessary", 1966 ), 1967 cast_suggestion, 1968 Applicability::MaybeIncorrect, // lossy conversion 1969 ); 1970 } 1971 true 1972 } 1973 (ty::Float(exp), ty::Int(found)) => { 1974 // if `found` is `None` (meaning found is `isize`), don't suggest `.into()` 1975 if exp.bit_width() > found.bit_width().unwrap_or(256) { 1976 err.multipart_suggestion_verbose( 1977 format!( 1978 "{}, producing the floating point representation of the integer", 1979 msg.clone(), 1980 ), 1981 into_suggestion, 1982 Applicability::MachineApplicable, 1983 ); 1984 } else if literal_is_ty_suffixed(expr) { 1985 err.multipart_suggestion_verbose( 1986 lit_msg, 1987 suffix_suggestion, 1988 Applicability::MachineApplicable, 1989 ); 1990 } else { 1991 // Missing try_into implementation for `{integer}` to `{float}` 1992 err.multipart_suggestion_verbose( 1993 format!( 1994 "{}, producing the floating point representation of the integer, \ 1995 rounded if necessary", 1996 &msg, 1997 ), 1998 cast_suggestion, 1999 Applicability::MaybeIncorrect, // lossy conversion 2000 ); 2001 } 2002 true 2003 } 2004 ( 2005 &ty::Uint(ty::UintTy::U32 | ty::UintTy::U64 | ty::UintTy::U128) 2006 | &ty::Int(ty::IntTy::I32 | ty::IntTy::I64 | ty::IntTy::I128), 2007 &ty::Char, 2008 ) => { 2009 err.multipart_suggestion_verbose( 2010 format!("{cast_msg}, since a `char` always occupies 4 bytes"), 2011 cast_suggestion, 2012 Applicability::MachineApplicable, 2013 ); 2014 true 2015 } 2016 _ => false, 2017 } 2018 } 2019 2020 /// Identify when the user has written `foo..bar()` instead of `foo.bar()`. suggest_method_call_on_range_literal( &self, err: &mut Diagnostic, expr: &hir::Expr<'tcx>, checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, )2021 pub fn suggest_method_call_on_range_literal( 2022 &self, 2023 err: &mut Diagnostic, 2024 expr: &hir::Expr<'tcx>, 2025 checked_ty: Ty<'tcx>, 2026 expected_ty: Ty<'tcx>, 2027 ) { 2028 if !hir::is_range_literal(expr) { 2029 return; 2030 } 2031 let hir::ExprKind::Struct( 2032 hir::QPath::LangItem(LangItem::Range, ..), 2033 [start, end], 2034 _, 2035 ) = expr.kind else { return; }; 2036 let parent = self.tcx.hir().parent_id(expr.hir_id); 2037 if let Some(hir::Node::ExprField(_)) = self.tcx.hir().find(parent) { 2038 // Ignore `Foo { field: a..Default::default() }` 2039 return; 2040 } 2041 let mut expr = end.expr; 2042 let mut expectation = Some(expected_ty); 2043 while let hir::ExprKind::MethodCall(_, rcvr, ..) = expr.kind { 2044 // Getting to the root receiver and asserting it is a fn call let's us ignore cases in 2045 // `tests/ui/methods/issues/issue-90315.stderr`. 2046 expr = rcvr; 2047 // If we have more than one layer of calls, then the expected ty 2048 // cannot guide the method probe. 2049 expectation = None; 2050 } 2051 let hir::ExprKind::Call(method_name, _) = expr.kind else { return; }; 2052 let ty::Adt(adt, _) = checked_ty.kind() else { return; }; 2053 if self.tcx.lang_items().range_struct() != Some(adt.did()) { 2054 return; 2055 } 2056 if let ty::Adt(adt, _) = expected_ty.kind() 2057 && self.tcx.lang_items().range_struct() == Some(adt.did()) 2058 { 2059 return; 2060 } 2061 // Check if start has method named end. 2062 let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = method_name.kind else { return; }; 2063 let [hir::PathSegment { ident, .. }] = p.segments else { return; }; 2064 let self_ty = self.typeck_results.borrow().expr_ty(start.expr); 2065 let Ok(_pick) = self.lookup_probe_for_diagnostic( 2066 *ident, 2067 self_ty, 2068 expr, 2069 probe::ProbeScope::AllTraits, 2070 expectation, 2071 ) else { return; }; 2072 let mut sugg = "."; 2073 let mut span = start.expr.span.between(end.expr.span); 2074 if span.lo() + BytePos(2) == span.hi() { 2075 // There's no space between the start, the range op and the end, suggest removal which 2076 // will be more noticeable than the replacement of `..` with `.`. 2077 span = span.with_lo(span.lo() + BytePos(1)); 2078 sugg = ""; 2079 } 2080 err.span_suggestion_verbose( 2081 span, 2082 "you likely meant to write a method call instead of a range", 2083 sugg, 2084 Applicability::MachineApplicable, 2085 ); 2086 } 2087 2088 /// Identify when the type error is because `()` is found in a binding that was assigned a 2089 /// block without a tail expression. suggest_return_binding_for_missing_tail_expr( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, )2090 fn suggest_return_binding_for_missing_tail_expr( 2091 &self, 2092 err: &mut Diagnostic, 2093 expr: &hir::Expr<'_>, 2094 checked_ty: Ty<'tcx>, 2095 expected_ty: Ty<'tcx>, 2096 ) { 2097 if !checked_ty.is_unit() { 2098 return; 2099 } 2100 let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else { return; }; 2101 let hir::def::Res::Local(hir_id) = path.res else { return; }; 2102 let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(hir_id) else { 2103 return; 2104 }; 2105 let Some(hir::Node::Local(hir::Local { 2106 ty: None, 2107 init: Some(init), 2108 .. 2109 })) = self.tcx.hir().find_parent(pat.hir_id) else { return; }; 2110 let hir::ExprKind::Block(block, None) = init.kind else { return; }; 2111 if block.expr.is_some() { 2112 return; 2113 } 2114 let [.., stmt] = block.stmts else { 2115 err.span_label(block.span, "this empty block is missing a tail expression"); 2116 return; 2117 }; 2118 let hir::StmtKind::Semi(tail_expr) = stmt.kind else { return; }; 2119 let Some(ty) = self.node_ty_opt(tail_expr.hir_id) else { return; }; 2120 if self.can_eq(self.param_env, expected_ty, ty) { 2121 err.span_suggestion_short( 2122 stmt.span.with_lo(tail_expr.span.hi()), 2123 "remove this semicolon", 2124 "", 2125 Applicability::MachineApplicable, 2126 ); 2127 } else { 2128 err.span_label(block.span, "this block is missing a tail expression"); 2129 } 2130 } 2131 note_wrong_return_ty_due_to_generic_arg( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, checked_ty: Ty<'tcx>, )2132 fn note_wrong_return_ty_due_to_generic_arg( 2133 &self, 2134 err: &mut Diagnostic, 2135 expr: &hir::Expr<'_>, 2136 checked_ty: Ty<'tcx>, 2137 ) { 2138 let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else { return; }; 2139 enum CallableKind { 2140 Function, 2141 Method, 2142 Constructor, 2143 } 2144 let mut maybe_emit_help = |def_id: hir::def_id::DefId, 2145 callable: rustc_span::symbol::Ident, 2146 args: &[hir::Expr<'_>], 2147 kind: CallableKind| { 2148 let arg_idx = args.iter().position(|a| a.hir_id == expr.hir_id).unwrap(); 2149 let fn_ty = self.tcx.type_of(def_id).skip_binder(); 2150 if !fn_ty.is_fn() { 2151 return; 2152 } 2153 let fn_sig = fn_ty.fn_sig(self.tcx).skip_binder(); 2154 let Some(&arg) = fn_sig.inputs().get(arg_idx + if matches!(kind, CallableKind::Method) { 1 } else { 0 }) else { return; }; 2155 if matches!(arg.kind(), ty::Param(_)) 2156 && fn_sig.output().contains(arg) 2157 && self.node_ty(args[arg_idx].hir_id) == checked_ty 2158 { 2159 let mut multi_span: MultiSpan = parent_expr.span.into(); 2160 multi_span.push_span_label( 2161 args[arg_idx].span, 2162 format!( 2163 "this argument influences the {} of `{}`", 2164 if matches!(kind, CallableKind::Constructor) { 2165 "type" 2166 } else { 2167 "return type" 2168 }, 2169 callable 2170 ), 2171 ); 2172 err.span_help( 2173 multi_span, 2174 format!( 2175 "the {} `{}` due to the type of the argument passed", 2176 match kind { 2177 CallableKind::Function => "return type of this call is", 2178 CallableKind::Method => "return type of this call is", 2179 CallableKind::Constructor => "type constructed contains", 2180 }, 2181 checked_ty 2182 ), 2183 ); 2184 } 2185 }; 2186 match parent_expr.kind { 2187 hir::ExprKind::Call(fun, args) => { 2188 let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else { return; }; 2189 let hir::def::Res::Def(kind, def_id) = path.res else { return; }; 2190 let callable_kind = if matches!(kind, hir::def::DefKind::Ctor(_, _)) { 2191 CallableKind::Constructor 2192 } else { 2193 CallableKind::Function 2194 }; 2195 maybe_emit_help(def_id, path.segments[0].ident, args, callable_kind); 2196 } 2197 hir::ExprKind::MethodCall(method, _receiver, args, _span) => { 2198 let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id) else { return; }; 2199 maybe_emit_help(def_id, method.ident, args, CallableKind::Method) 2200 } 2201 _ => return, 2202 } 2203 } 2204 } 2205 2206 pub enum TypeMismatchSource<'tcx> { 2207 /// Expected the binding to have the given type, but it was found to have 2208 /// a different type. Find out when that type first became incompatible. 2209 Ty(Ty<'tcx>), 2210 /// When we fail during method argument checking, try to find out if a previous 2211 /// expression has constrained the method's receiver in a way that makes the 2212 /// argument's type incompatible. 2213 Arg { call_expr: &'tcx hir::Expr<'tcx>, incompatible_arg: usize }, 2214 } 2215