Suggest associated method on deref types

This commit is contained in:
Michael Goulet 2022-09-03 07:24:55 +00:00
parent 0421444f8f
commit 12a4952369
3 changed files with 80 additions and 2 deletions

View File

@ -16,8 +16,8 @@
use rustc_middle::traits::util::supertraits;
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
use rustc_middle::ty::print::with_crate_prefix;
use rustc_middle::ty::ToPolyTraitRef;
use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeVisitable};
use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span};
@ -30,7 +30,7 @@
use std::cmp::Ordering;
use std::iter;
use super::probe::{Mode, ProbeScope};
use super::probe::{IsSuggestion, Mode, ProbeScope};
use super::{CandidateSource, MethodError, NoMatchData};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@ -1069,6 +1069,8 @@ trait bound{s}",
}
}
self.check_for_deref_method(&mut err, source, rcvr_ty, item_name);
return Some(err);
}
@ -1651,6 +1653,62 @@ fn suggest_derive(
}
}
fn check_for_deref_method(
&self,
err: &mut Diagnostic,
self_source: SelfSource<'tcx>,
rcvr_ty: Ty<'tcx>,
item_name: Ident,
) {
let SelfSource::QPath(ty) = self_source else { return; };
for (deref_ty, _) in self.autoderef(rustc_span::DUMMY_SP, rcvr_ty).skip(1) {
if let Ok(pick) = self.probe_for_name(
ty.span,
Mode::Path,
item_name,
IsSuggestion(true),
deref_ty,
ty.hir_id,
ProbeScope::TraitsInScope,
) {
if deref_ty.is_suggestable(self.tcx, true)
// If this method receives `&self`, then the provided
// argument _should_ coerce, so it's valid to suggest
// just changing the path.
&& pick.item.fn_has_self_parameter
&& let Some(self_ty) =
self.tcx.fn_sig(pick.item.def_id).inputs().skip_binder().get(0)
&& self_ty.is_ref()
{
let suggested_path = match deref_ty.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Adt(_, _)
| ty::Str
| ty::Projection(_)
| ty::Param(_) => format!("{deref_ty}"),
_ => format!("<{deref_ty}>"),
};
err.span_suggestion_verbose(
ty.span,
format!("the function `{item_name}` is implemented on `{deref_ty}`"),
suggested_path,
Applicability::MaybeIncorrect,
);
} else {
err.span_note(
ty.span,
format!("the function `{item_name}` is implemented on `{deref_ty}`"),
);
}
return;
}
}
}
/// Print out the type for use in value namespace.
fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
match ty.kind() {

View File

@ -0,0 +1,6 @@
fn main() {
let vec = Vec::new();
Vec::contains(&vec, &0);
//~^ ERROR no function or associated item named `contains` found for struct `Vec<_, _>` in the current scope
//~| HELP the function `contains` is implemented on `[_]`
}

View File

@ -0,0 +1,14 @@
error[E0599]: no function or associated item named `contains` found for struct `Vec<_, _>` in the current scope
--> $DIR/deref-path-method.rs:3:10
|
LL | Vec::contains(&vec, &0);
| ^^^^^^^^ function or associated item not found in `Vec<_, _>`
|
help: the function `contains` is implemented on `[_]`
|
LL | <[_]>::contains(&vec, &0);
| ~~~~~
error: aborting due to previous error
For more information about this error, try `rustc --explain E0599`.