|
1 | 1 | use crate::FnCtxt;
|
2 | 2 | use rustc_ast::util::parser::PREC_POSTFIX;
|
| 3 | +use rustc_errors::MultiSpan; |
3 | 4 | use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
4 | 5 | use rustc_hir as hir;
|
5 | 6 | use rustc_hir::def::CtorKind;
|
@@ -36,6 +37,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
36 | 37 | return;
|
37 | 38 | }
|
38 | 39 |
|
| 40 | + self.annotate_alternative_method_deref(err, expr, error); |
| 41 | + |
39 | 42 | // Use `||` to give these suggestions a precedence
|
40 | 43 | let _ = self.suggest_missing_parentheses(err, expr)
|
41 | 44 | || self.suggest_remove_last_method_call(err, expr, expected)
|
@@ -316,6 +319,95 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
316 | 319 | }
|
317 | 320 | }
|
318 | 321 |
|
| 322 | + fn annotate_alternative_method_deref( |
| 323 | + &self, |
| 324 | + err: &mut Diagnostic, |
| 325 | + expr: &hir::Expr<'_>, |
| 326 | + error: Option<TypeError<'tcx>>, |
| 327 | + ) { |
| 328 | + let parent = self.tcx.hir().get_parent_node(expr.hir_id); |
| 329 | + let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {return;}; |
| 330 | + let Some(hir::Node::Expr(hir::Expr { |
| 331 | + kind: hir::ExprKind::Assign(lhs, rhs, _), .. |
| 332 | + })) = self.tcx.hir().find(parent) else {return; }; |
| 333 | + if rhs.hir_id != expr.hir_id || expected.is_closure() { |
| 334 | + return; |
| 335 | + } |
| 336 | + let hir::ExprKind::Unary(hir::UnOp::Deref, deref) = lhs.kind else { return; }; |
| 337 | + let hir::ExprKind::MethodCall(path, base, args, _) = deref.kind else { return; }; |
| 338 | + let self_ty = self.typeck_results.borrow().expr_ty_adjusted_opt(base).unwrap(); |
| 339 | + let pick = self |
| 340 | + .probe_for_name( |
| 341 | + probe::Mode::MethodCall, |
| 342 | + path.ident, |
| 343 | + probe::IsSuggestion(true), |
| 344 | + self_ty, |
| 345 | + deref.hir_id, |
| 346 | + probe::ProbeScope::TraitsInScope, |
| 347 | + ) |
| 348 | + .unwrap(); |
| 349 | + let methods = self.probe_for_name_many( |
| 350 | + probe::Mode::MethodCall, |
| 351 | + path.ident, |
| 352 | + probe::IsSuggestion(true), |
| 353 | + self_ty, |
| 354 | + deref.hir_id, |
| 355 | + probe::ProbeScope::AllTraits, |
| 356 | + ); |
| 357 | + let suggestions: Vec<_> = methods |
| 358 | + .into_iter() |
| 359 | + .filter(|m| m.def_id != pick.item.def_id) |
| 360 | + .map(|m| { |
| 361 | + let substs = ty::InternalSubsts::for_item(self.tcx, m.def_id, |param, _| { |
| 362 | + self.var_for_def(deref.span, param) |
| 363 | + }); |
| 364 | + vec![ |
| 365 | + ( |
| 366 | + deref.span.until(base.span), |
| 367 | + format!( |
| 368 | + "{}({}", |
| 369 | + with_no_trimmed_paths!( |
| 370 | + self.tcx.def_path_str_with_substs(m.def_id, substs,) |
| 371 | + ), |
| 372 | + match self.tcx.fn_sig(m.def_id).input(0).skip_binder().kind() { |
| 373 | + ty::Ref(_, _, hir::Mutability::Mut) => "&mut ", |
| 374 | + ty::Ref(_, _, _) => "&", |
| 375 | + _ => "", |
| 376 | + }, |
| 377 | + ), |
| 378 | + ), |
| 379 | + match &args[..] { |
| 380 | + [] => (base.span.shrink_to_hi().with_hi(deref.span.hi()), ")".to_string()), |
| 381 | + [first, ..] => (base.span.until(first.span), String::new()), |
| 382 | + }, |
| 383 | + ] |
| 384 | + }) |
| 385 | + .collect(); |
| 386 | + if suggestions.is_empty() { |
| 387 | + return; |
| 388 | + } |
| 389 | + let mut path_span: MultiSpan = path.ident.span.into(); |
| 390 | + path_span.push_span_label( |
| 391 | + path.ident.span, |
| 392 | + format!( |
| 393 | + "refers to `{}`", |
| 394 | + with_no_trimmed_paths!(self.tcx.def_path_str(pick.item.def_id)), |
| 395 | + ), |
| 396 | + ); |
| 397 | + err.span_note( |
| 398 | + path_span, |
| 399 | + &format!( |
| 400 | + "there are multiple methods with the same name, `{}` refers to `{}` in the method call", |
| 401 | + path.ident, |
| 402 | + with_no_trimmed_paths!(self.tcx.def_path_str(pick.item.def_id)), |
| 403 | + )); |
| 404 | + err.multipart_suggestions( |
| 405 | + "you might have meant to invoke a different method, you can use the fully-qualified path", |
| 406 | + suggestions, |
| 407 | + Applicability::MaybeIncorrect, |
| 408 | + ); |
| 409 | + } |
| 410 | + |
319 | 411 | /// If the expected type is an enum (Issue #55250) with any variants whose
|
320 | 412 | /// sole field is of the found type, suggest such variants. (Issue #42764)
|
321 | 413 | fn suggest_compatible_variants(
|
|
0 commit comments