parent
caa64e5b5e
commit
34b9594f6d
@ -1,5 +1,6 @@
|
|||||||
use crate::FnCtxt;
|
use crate::FnCtxt;
|
||||||
use rustc_ast::util::parser::PREC_POSTFIX;
|
use rustc_ast::util::parser::PREC_POSTFIX;
|
||||||
|
use rustc_errors::MultiSpan;
|
||||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::CtorKind;
|
use rustc_hir::def::CtorKind;
|
||||||
@ -36,6 +37,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.annotate_alternative_method_deref(err, expr, error);
|
||||||
|
|
||||||
// Use `||` to give these suggestions a precedence
|
// Use `||` to give these suggestions a precedence
|
||||||
let _ = self.suggest_missing_parentheses(err, expr)
|
let _ = self.suggest_missing_parentheses(err, expr)
|
||||||
|| self.suggest_remove_last_method_call(err, expr, expected)
|
|| self.suggest_remove_last_method_call(err, expr, expected)
|
||||||
@ -316,6 +319,95 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn annotate_alternative_method_deref(
|
||||||
|
&self,
|
||||||
|
err: &mut Diagnostic,
|
||||||
|
expr: &hir::Expr<'_>,
|
||||||
|
error: Option<TypeError<'tcx>>,
|
||||||
|
) {
|
||||||
|
let parent = self.tcx.hir().get_parent_node(expr.hir_id);
|
||||||
|
let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {return;};
|
||||||
|
let Some(hir::Node::Expr(hir::Expr {
|
||||||
|
kind: hir::ExprKind::Assign(lhs, rhs, _), ..
|
||||||
|
})) = self.tcx.hir().find(parent) else {return; };
|
||||||
|
if rhs.hir_id != expr.hir_id || expected.is_closure() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let hir::ExprKind::Unary(hir::UnOp::Deref, deref) = lhs.kind else { return; };
|
||||||
|
let hir::ExprKind::MethodCall(path, base, args, _) = deref.kind else { return; };
|
||||||
|
let self_ty = self.typeck_results.borrow().expr_ty_adjusted_opt(base).unwrap();
|
||||||
|
let pick = self
|
||||||
|
.probe_for_name(
|
||||||
|
probe::Mode::MethodCall,
|
||||||
|
path.ident,
|
||||||
|
probe::IsSuggestion(true),
|
||||||
|
self_ty,
|
||||||
|
deref.hir_id,
|
||||||
|
probe::ProbeScope::TraitsInScope,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let methods = self.probe_for_name_many(
|
||||||
|
probe::Mode::MethodCall,
|
||||||
|
path.ident,
|
||||||
|
probe::IsSuggestion(true),
|
||||||
|
self_ty,
|
||||||
|
deref.hir_id,
|
||||||
|
probe::ProbeScope::AllTraits,
|
||||||
|
);
|
||||||
|
let suggestions: Vec<_> = methods
|
||||||
|
.into_iter()
|
||||||
|
.filter(|m| m.def_id != pick.item.def_id)
|
||||||
|
.map(|m| {
|
||||||
|
let substs = ty::InternalSubsts::for_item(self.tcx, m.def_id, |param, _| {
|
||||||
|
self.var_for_def(deref.span, param)
|
||||||
|
});
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
deref.span.until(base.span),
|
||||||
|
format!(
|
||||||
|
"{}({}",
|
||||||
|
with_no_trimmed_paths!(
|
||||||
|
self.tcx.def_path_str_with_substs(m.def_id, substs,)
|
||||||
|
),
|
||||||
|
match self.tcx.fn_sig(m.def_id).input(0).skip_binder().kind() {
|
||||||
|
ty::Ref(_, _, hir::Mutability::Mut) => "&mut ",
|
||||||
|
ty::Ref(_, _, _) => "&",
|
||||||
|
_ => "",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
match &args[..] {
|
||||||
|
[] => (base.span.shrink_to_hi().with_hi(deref.span.hi()), ")".to_string()),
|
||||||
|
[first, ..] => (base.span.until(first.span), String::new()),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
if suggestions.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut path_span: MultiSpan = path.ident.span.into();
|
||||||
|
path_span.push_span_label(
|
||||||
|
path.ident.span,
|
||||||
|
format!(
|
||||||
|
"refers to `{}`",
|
||||||
|
with_no_trimmed_paths!(self.tcx.def_path_str(pick.item.def_id)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
err.span_note(
|
||||||
|
path_span,
|
||||||
|
&format!(
|
||||||
|
"there are multiple methods with the same name, `{}` refers to `{}` in the method call",
|
||||||
|
path.ident,
|
||||||
|
with_no_trimmed_paths!(self.tcx.def_path_str(pick.item.def_id)),
|
||||||
|
));
|
||||||
|
err.multipart_suggestions(
|
||||||
|
"you might have meant to invoke a different method, you can use the fully-qualified path",
|
||||||
|
suggestions,
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// If the expected type is an enum (Issue #55250) with any variants whose
|
/// If the expected type is an enum (Issue #55250) with any variants whose
|
||||||
/// sole field is of the found type, suggest such variants. (Issue #42764)
|
/// sole field is of the found type, suggest such variants. (Issue #42764)
|
||||||
fn suggest_compatible_variants(
|
fn suggest_compatible_variants(
|
||||||
|
@ -322,6 +322,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self))]
|
||||||
|
pub fn probe_for_name_many(
|
||||||
|
&self,
|
||||||
|
mode: Mode,
|
||||||
|
item_name: Ident,
|
||||||
|
is_suggestion: IsSuggestion,
|
||||||
|
self_ty: Ty<'tcx>,
|
||||||
|
scope_expr_id: hir::HirId,
|
||||||
|
scope: ProbeScope,
|
||||||
|
) -> Vec<ty::AssocItem> {
|
||||||
|
self.probe_op(
|
||||||
|
item_name.span,
|
||||||
|
mode,
|
||||||
|
Some(item_name),
|
||||||
|
None,
|
||||||
|
is_suggestion,
|
||||||
|
self_ty,
|
||||||
|
scope_expr_id,
|
||||||
|
scope,
|
||||||
|
|probe_cx| {
|
||||||
|
Ok(probe_cx
|
||||||
|
.inherent_candidates
|
||||||
|
.iter()
|
||||||
|
.chain(&probe_cx.extension_candidates)
|
||||||
|
// .filter(|candidate| candidate_filter(&candidate.item))
|
||||||
|
.map(|candidate| candidate.item)
|
||||||
|
.collect())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
fn probe_op<OP, R>(
|
fn probe_op<OP, R>(
|
||||||
&'a self,
|
&'a self,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
10
src/test/ui/suggestions/shadowed-lplace-method.fixed
Normal file
10
src/test/ui/suggestions/shadowed-lplace-method.fixed
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// run-rustfix
|
||||||
|
#![allow(unused_imports)]
|
||||||
|
use std::borrow::BorrowMut;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let rc = Rc::new(RefCell::new(true));
|
||||||
|
*std::cell::RefCell::<_>::borrow_mut(&rc) = false; //~ ERROR E0308
|
||||||
|
}
|
10
src/test/ui/suggestions/shadowed-lplace-method.rs
Normal file
10
src/test/ui/suggestions/shadowed-lplace-method.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// run-rustfix
|
||||||
|
#![allow(unused_imports)]
|
||||||
|
use std::borrow::BorrowMut;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let rc = Rc::new(RefCell::new(true));
|
||||||
|
*rc.borrow_mut() = false; //~ ERROR E0308
|
||||||
|
}
|
23
src/test/ui/suggestions/shadowed-lplace-method.stderr
Normal file
23
src/test/ui/suggestions/shadowed-lplace-method.stderr
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/shadowed-lplace-method.rs:9:24
|
||||||
|
|
|
||||||
|
LL | *rc.borrow_mut() = false;
|
||||||
|
| ---------------- ^^^^^ expected struct `Rc`, found `bool`
|
||||||
|
| |
|
||||||
|
| expected due to the type of this binding
|
||||||
|
|
|
||||||
|
= note: expected struct `Rc<RefCell<bool>>`
|
||||||
|
found type `bool`
|
||||||
|
note: there are multiple methods with the same name, `borrow_mut` refers to `std::borrow::BorrowMut::borrow_mut` in the method call
|
||||||
|
--> $DIR/shadowed-lplace-method.rs:9:9
|
||||||
|
|
|
||||||
|
LL | *rc.borrow_mut() = false;
|
||||||
|
| ^^^^^^^^^^ refers to `std::borrow::BorrowMut::borrow_mut`
|
||||||
|
help: you might have meant to invoke a different method, you can use the fully-qualified path
|
||||||
|
|
|
||||||
|
LL | *std::cell::RefCell::<_>::borrow_mut(&rc) = false;
|
||||||
|
| +++++++++++++++++++++++++++++++++++++ ~
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
x
Reference in New Issue
Block a user