Change Levensthein-based method to a single suggestion
The convention for suggesting close matches is to provide at most one match (the closest one). Change the suggestions for misspelt method names to obey that.
This commit is contained in:
parent
09defbcb5b
commit
4963394f86
@ -68,24 +68,24 @@ pub enum MethodError<'tcx> {
|
||||
// could lead to matches if satisfied, and a list of not-in-scope traits which may work.
|
||||
pub struct NoMatchData<'tcx> {
|
||||
pub static_candidates: Vec<CandidateSource>,
|
||||
pub lev_candidates: Vec<ty::AssociatedItem>,
|
||||
pub unsatisfied_predicates: Vec<TraitRef<'tcx>>,
|
||||
pub out_of_scope_traits: Vec<DefId>,
|
||||
pub lev_candidate: Option<ty::AssociatedItem>,
|
||||
pub mode: probe::Mode,
|
||||
}
|
||||
|
||||
impl<'tcx> NoMatchData<'tcx> {
|
||||
pub fn new(static_candidates: Vec<CandidateSource>,
|
||||
lev_candidates: Vec<ty::AssociatedItem>,
|
||||
unsatisfied_predicates: Vec<TraitRef<'tcx>>,
|
||||
out_of_scope_traits: Vec<DefId>,
|
||||
lev_candidate: Option<ty::AssociatedItem>,
|
||||
mode: probe::Mode)
|
||||
-> Self {
|
||||
NoMatchData {
|
||||
static_candidates,
|
||||
lev_candidates,
|
||||
unsatisfied_predicates,
|
||||
out_of_scope_traits,
|
||||
lev_candidate,
|
||||
mode,
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ use rustc::infer::type_variable::TypeVariableOrigin;
|
||||
use rustc::util::nodemap::FxHashSet;
|
||||
use rustc::infer::{self, InferOk};
|
||||
use syntax::ast;
|
||||
use syntax::util::lev_distance::lev_distance;
|
||||
use syntax::util::lev_distance::{lev_distance, find_best_match_for_name};
|
||||
use syntax_pos::Span;
|
||||
use rustc::hir;
|
||||
use std::mem;
|
||||
@ -248,7 +248,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(),
|
||||
Vec::new(),
|
||||
Vec::new(),
|
||||
Vec::new(),
|
||||
None,
|
||||
mode)))
|
||||
}
|
||||
}
|
||||
@ -806,12 +806,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
if let Some(def) = private_candidate {
|
||||
return Err(MethodError::PrivateMatch(def, out_of_scope_traits));
|
||||
}
|
||||
let lev_candidates = self.probe_for_lev_candidates()?;
|
||||
let lev_candidate = self.probe_for_lev_candidate()?;
|
||||
|
||||
Err(MethodError::NoMatch(NoMatchData::new(static_candidates,
|
||||
lev_candidates,
|
||||
unsatisfied_predicates,
|
||||
out_of_scope_traits,
|
||||
lev_candidate,
|
||||
self.mode)))
|
||||
}
|
||||
|
||||
@ -1133,9 +1133,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Similarly to `probe_for_return_type`, this method attempts to find candidate methods where
|
||||
/// the method name may have been misspelt.
|
||||
fn probe_for_lev_candidates(&mut self) -> Result<Vec<ty::AssociatedItem>, MethodError<'tcx>> {
|
||||
/// Similarly to `probe_for_return_type`, this method attempts to find the best matching
|
||||
/// candidate method where the method name may have been misspelt. Similarly to other
|
||||
/// Levenshtein based suggestions, we provide at most one such suggestion.
|
||||
fn probe_for_lev_candidate(&mut self) -> Result<Option<ty::AssociatedItem>, MethodError<'tcx>> {
|
||||
debug!("Probing for method names similar to {:?}",
|
||||
self.method_name);
|
||||
|
||||
@ -1149,7 +1150,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
let method_names = pcx.candidate_method_names();
|
||||
pcx.allow_similar_names = false;
|
||||
Ok(method_names
|
||||
let applicable_close_candidates: Vec<ty::AssociatedItem> = method_names
|
||||
.iter()
|
||||
.filter_map(|&method_name| {
|
||||
pcx.reset();
|
||||
@ -1162,7 +1163,21 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
.and_then(|pick| Some(pick.item))
|
||||
})
|
||||
})
|
||||
.collect())
|
||||
.collect();
|
||||
|
||||
if applicable_close_candidates.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
let best_name = {
|
||||
let names = applicable_close_candidates.iter().map(|cand| &cand.name);
|
||||
find_best_match_for_name(names,
|
||||
&self.method_name.unwrap().as_str(),
|
||||
None)
|
||||
}.unwrap();
|
||||
Ok(applicable_close_candidates
|
||||
.into_iter()
|
||||
.find(|method| method.name == best_name))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -162,9 +162,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
match error {
|
||||
MethodError::NoMatch(NoMatchData { static_candidates: static_sources,
|
||||
lev_candidates,
|
||||
unsatisfied_predicates,
|
||||
out_of_scope_traits,
|
||||
lev_candidate,
|
||||
mode,
|
||||
.. }) => {
|
||||
let tcx = self.tcx;
|
||||
@ -284,10 +284,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
rcvr_expr,
|
||||
out_of_scope_traits);
|
||||
|
||||
if !lev_candidates.is_empty() {
|
||||
for meth in lev_candidates.iter().take(5) {
|
||||
err.help(&format!("did you mean `{}`?", meth.name));
|
||||
}
|
||||
if let Some(lev_candidate) = lev_candidate {
|
||||
err.help(&format!("did you mean `{}`?", lev_candidate.name));
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
@ -30,9 +30,11 @@ fn main() {
|
||||
let s = "foo".to_string();
|
||||
let _ = s.is_emtpy();
|
||||
|
||||
// Generates a warning, both for count_ones and count_zeros
|
||||
// Generates a warning for `count_zeros()`. `count_ones()` is also a close
|
||||
// match, but the former is closer.
|
||||
let _ = 63u32.count_eos();
|
||||
let _ = 63u32.count_o(); // Does not generate a warning
|
||||
|
||||
// Does not generate a warning
|
||||
let _ = 63u32.count_o();
|
||||
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,6 @@ error[E0599]: no method named `bat` found for type `Foo` in the current scope
|
||||
| ^^^
|
||||
|
|
||||
= help: did you mean `bar`?
|
||||
= help: did you mean `baz`?
|
||||
|
||||
error[E0599]: no method named `is_emtpy` found for type `std::string::String` in the current scope
|
||||
--> $DIR/suggest-methods.rs:31:15
|
||||
@ -16,18 +15,17 @@ error[E0599]: no method named `is_emtpy` found for type `std::string::String` in
|
||||
= help: did you mean `is_empty`?
|
||||
|
||||
error[E0599]: no method named `count_eos` found for type `u32` in the current scope
|
||||
--> $DIR/suggest-methods.rs:34:19
|
||||
--> $DIR/suggest-methods.rs:35:19
|
||||
|
|
||||
34 | let _ = 63u32.count_eos();
|
||||
35 | let _ = 63u32.count_eos();
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= help: did you mean `count_ones`?
|
||||
= help: did you mean `count_zeros`?
|
||||
|
||||
error[E0599]: no method named `count_o` found for type `u32` in the current scope
|
||||
--> $DIR/suggest-methods.rs:35:19
|
||||
--> $DIR/suggest-methods.rs:38:19
|
||||
|
|
||||
35 | let _ = 63u32.count_o(); // Does not generate a warning
|
||||
38 | let _ = 63u32.count_o();
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
Loading…
Reference in New Issue
Block a user