mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 06:22:00 +00:00
review comments: clean up
This commit is contained in:
parent
f566867ace
commit
b59bd7fd16
@ -563,80 +563,73 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
};
|
||||
|
||||
let suggest_confusable = |err: &mut Diagnostic| {
|
||||
if let Some(call_name) = call_ident
|
||||
&& let Some(callee_ty) = callee_ty
|
||||
{
|
||||
let input_types: Vec<Ty<'_>> = provided_arg_tys.iter().map(|(ty, _)| *ty).collect();
|
||||
// Check for other methods in the following order
|
||||
// - methods marked as `rustc_confusables` with the provided arguments
|
||||
// - methods with the same argument type/count and short levenshtein distance
|
||||
// - methods marked as `rustc_confusables` (done)
|
||||
// - methods with short levenshtein distance
|
||||
let call_name = call_ident?;
|
||||
let callee_ty = callee_ty?;
|
||||
let input_types: Vec<Ty<'_>> = provided_arg_tys.iter().map(|(ty, _)| *ty).collect();
|
||||
// Check for other methods in the following order
|
||||
// - methods marked as `rustc_confusables` with the provided arguments
|
||||
// - methods with the same argument type/count and short levenshtein distance
|
||||
// - methods marked as `rustc_confusables` (done)
|
||||
// - methods with short levenshtein distance
|
||||
|
||||
// Look for commonly confusable method names considering arguments.
|
||||
self.confusable_method_name(
|
||||
err,
|
||||
callee_ty.peel_refs(),
|
||||
call_name,
|
||||
Some(input_types.clone()),
|
||||
)
|
||||
.or_else(|| {
|
||||
// Look for method names with short levenshtein distance, considering arguments.
|
||||
if let Some((assoc, fn_sig)) = similar_assoc(call_name)
|
||||
&& fn_sig.inputs()[1..]
|
||||
.iter()
|
||||
.zip(input_types.iter())
|
||||
.all(|(expected, found)| self.can_coerce(*expected, *found))
|
||||
&& fn_sig.inputs()[1..].len() == input_types.len()
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
call_name.span,
|
||||
format!("you might have meant to use `{}`", assoc.name),
|
||||
assoc.name,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
return Some(assoc.name);
|
||||
}
|
||||
None
|
||||
})
|
||||
.or_else(|| {
|
||||
// Look for commonly confusable method names disregarding arguments.
|
||||
self.confusable_method_name(err, callee_ty.peel_refs(), call_name, None)
|
||||
})
|
||||
.or_else(|| {
|
||||
// Look for similarly named methods with levenshtein distance with the right
|
||||
// number of arguments.
|
||||
if let Some((assoc, fn_sig)) = similar_assoc(call_name)
|
||||
&& fn_sig.inputs()[1..].len() == input_types.len()
|
||||
{
|
||||
err.span_note(
|
||||
tcx.def_span(assoc.def_id),
|
||||
format!(
|
||||
"there's is a method with similar name `{}`, but the arguments \
|
||||
don't match",
|
||||
assoc.name,
|
||||
),
|
||||
);
|
||||
return Some(assoc.name);
|
||||
}
|
||||
None
|
||||
})
|
||||
.or_else(|| {
|
||||
// Fallthrough: look for similarly named methods with levenshtein distance.
|
||||
if let Some((assoc, _)) = similar_assoc(call_name) {
|
||||
err.span_note(
|
||||
tcx.def_span(assoc.def_id),
|
||||
format!(
|
||||
"there's is a method with similar name `{}`, but their argument \
|
||||
count doesn't match",
|
||||
assoc.name,
|
||||
),
|
||||
);
|
||||
return Some(assoc.name);
|
||||
}
|
||||
None
|
||||
});
|
||||
// Look for commonly confusable method names considering arguments.
|
||||
if let Some(name) = self.confusable_method_name(
|
||||
err,
|
||||
callee_ty.peel_refs(),
|
||||
call_name,
|
||||
Some(input_types.clone()),
|
||||
) {
|
||||
return Some(name);
|
||||
}
|
||||
// Look for method names with short levenshtein distance, considering arguments.
|
||||
if let Some((assoc, fn_sig)) = similar_assoc(call_name)
|
||||
&& fn_sig.inputs()[1..]
|
||||
.iter()
|
||||
.zip(input_types.iter())
|
||||
.all(|(expected, found)| self.can_coerce(*expected, *found))
|
||||
&& fn_sig.inputs()[1..].len() == input_types.len()
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
call_name.span,
|
||||
format!("you might have meant to use `{}`", assoc.name),
|
||||
assoc.name,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
return Some(assoc.name);
|
||||
}
|
||||
// Look for commonly confusable method names disregarding arguments.
|
||||
if let Some(name) =
|
||||
self.confusable_method_name(err, callee_ty.peel_refs(), call_name, None)
|
||||
{
|
||||
return Some(name);
|
||||
}
|
||||
// Look for similarly named methods with levenshtein distance with the right
|
||||
// number of arguments.
|
||||
if let Some((assoc, fn_sig)) = similar_assoc(call_name)
|
||||
&& fn_sig.inputs()[1..].len() == input_types.len()
|
||||
{
|
||||
err.span_note(
|
||||
tcx.def_span(assoc.def_id),
|
||||
format!(
|
||||
"there's is a method with similar name `{}`, but the arguments don't match",
|
||||
assoc.name,
|
||||
),
|
||||
);
|
||||
return Some(assoc.name);
|
||||
}
|
||||
// Fallthrough: look for similarly named methods with levenshtein distance.
|
||||
if let Some((assoc, _)) = similar_assoc(call_name) {
|
||||
err.span_note(
|
||||
tcx.def_span(assoc.def_id),
|
||||
format!(
|
||||
"there's is a method with similar name `{}`, but their argument count \
|
||||
doesn't match",
|
||||
assoc.name,
|
||||
),
|
||||
);
|
||||
return Some(assoc.name);
|
||||
}
|
||||
None
|
||||
};
|
||||
// A "softer" version of the `demand_compatible`, which checks types without persisting them,
|
||||
// and treats error types differently
|
||||
|
@ -1358,94 +1358,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// ...or if we already suggested that name because of `rustc_confusable` annotation.
|
||||
&& Some(similar_candidate.name) != confusable_suggested
|
||||
{
|
||||
let def_kind = similar_candidate.kind.as_def_kind();
|
||||
let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
|
||||
// Methods are defined within the context of a struct and their first parameter
|
||||
// is always `self`, which represents the instance of the struct the method is
|
||||
// being called on Associated functions don’t take self as a parameter and they are
|
||||
// not methods because they don’t have an instance of the struct to work with.
|
||||
if def_kind == DefKind::AssocFn {
|
||||
let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
|
||||
let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
|
||||
let fn_sig =
|
||||
self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig);
|
||||
if similar_candidate.fn_has_self_parameter {
|
||||
if let Some(args) = args
|
||||
&& fn_sig.inputs()[1..].len() == args.len()
|
||||
{
|
||||
// We found a method with the same number of arguments as the method
|
||||
// call expression the user wrote.
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
format!("there is {an} method with a similar name"),
|
||||
similar_candidate.name,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
// We found a method but either the expression is not a method call or
|
||||
// the argument count didn't match.
|
||||
err.span_help(
|
||||
tcx.def_span(similar_candidate.def_id),
|
||||
format!(
|
||||
"there is {an} method `{}` with a similar name{}",
|
||||
similar_candidate.name,
|
||||
if let None = args {
|
||||
""
|
||||
} else {
|
||||
", but with different arguments"
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
} else if let Some(args) = args
|
||||
&& fn_sig.inputs().len() == args.len()
|
||||
{
|
||||
// We have fn call expression and the argument count match the associated
|
||||
// function we found.
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
format!(
|
||||
"there is {an} {} with a similar name",
|
||||
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
|
||||
),
|
||||
similar_candidate.name,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.span_help(
|
||||
tcx.def_span(similar_candidate.def_id),
|
||||
format!(
|
||||
"there is {an} {} `{}` with a similar name",
|
||||
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
|
||||
similar_candidate.name,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else if let Mode::Path = mode
|
||||
&& args.unwrap_or(&[]).is_empty()
|
||||
{
|
||||
// We have an associated item syntax and we found something that isn't an fn.
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
format!(
|
||||
"there is {an} {} with a similar name",
|
||||
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
|
||||
),
|
||||
similar_candidate.name,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
// The expression is a function or method call, but the item we found is an
|
||||
// associated const or type.
|
||||
err.span_help(
|
||||
tcx.def_span(similar_candidate.def_id),
|
||||
format!(
|
||||
"there is {an} {} `{}` with a similar name",
|
||||
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
|
||||
similar_candidate.name,
|
||||
),
|
||||
);
|
||||
}
|
||||
self.find_likely_intended_associated_item(
|
||||
&mut err,
|
||||
similar_candidate,
|
||||
span,
|
||||
args,
|
||||
mode,
|
||||
);
|
||||
}
|
||||
}
|
||||
// If an appropriate error source is not found, check method chain for possible candiates
|
||||
@ -1497,6 +1416,100 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
Some(err)
|
||||
}
|
||||
|
||||
fn find_likely_intended_associated_item(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
similar_candidate: ty::AssocItem,
|
||||
span: Span,
|
||||
args: Option<&'tcx [hir::Expr<'tcx>]>,
|
||||
mode: Mode,
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
let def_kind = similar_candidate.kind.as_def_kind();
|
||||
let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
|
||||
// Methods are defined within the context of a struct and their first parameter
|
||||
// is always `self`, which represents the instance of the struct the method is
|
||||
// being called on Associated functions don’t take self as a parameter and they are
|
||||
// not methods because they don’t have an instance of the struct to work with.
|
||||
if def_kind == DefKind::AssocFn {
|
||||
let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
|
||||
let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
|
||||
let fn_sig = self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig);
|
||||
if similar_candidate.fn_has_self_parameter {
|
||||
if let Some(args) = args
|
||||
&& fn_sig.inputs()[1..].len() == args.len()
|
||||
{
|
||||
// We found a method with the same number of arguments as the method
|
||||
// call expression the user wrote.
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
format!("there is {an} method with a similar name"),
|
||||
similar_candidate.name,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
// We found a method but either the expression is not a method call or
|
||||
// the argument count didn't match.
|
||||
err.span_help(
|
||||
tcx.def_span(similar_candidate.def_id),
|
||||
format!(
|
||||
"there is {an} method `{}` with a similar name{}",
|
||||
similar_candidate.name,
|
||||
if let None = args { "" } else { ", but with different arguments" },
|
||||
),
|
||||
);
|
||||
}
|
||||
} else if let Some(args) = args
|
||||
&& fn_sig.inputs().len() == args.len()
|
||||
{
|
||||
// We have fn call expression and the argument count match the associated
|
||||
// function we found.
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
format!(
|
||||
"there is {an} {} with a similar name",
|
||||
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
|
||||
),
|
||||
similar_candidate.name,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.span_help(
|
||||
tcx.def_span(similar_candidate.def_id),
|
||||
format!(
|
||||
"there is {an} {} `{}` with a similar name",
|
||||
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
|
||||
similar_candidate.name,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else if let Mode::Path = mode
|
||||
&& args.unwrap_or(&[]).is_empty()
|
||||
{
|
||||
// We have an associated item syntax and we found something that isn't an fn.
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
format!(
|
||||
"there is {an} {} with a similar name",
|
||||
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
|
||||
),
|
||||
similar_candidate.name,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
// The expression is a function or method call, but the item we found is an
|
||||
// associated const or type.
|
||||
err.span_help(
|
||||
tcx.def_span(similar_candidate.def_id),
|
||||
format!(
|
||||
"there is {an} {} `{}` with a similar name",
|
||||
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
|
||||
similar_candidate.name,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn confusable_method_name(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
|
Loading…
Reference in New Issue
Block a user