diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2024-02-14 18:11:19 +0000 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2024-02-22 18:05:28 +0000 |
| commit | b59bd7fd16d6dfd3d09d1d708325d39763ec0ec7 (patch) | |
| tree | 437c5fb6deb9efa2e852b0d3baeb0bacda7ffad6 | |
| parent | f566867ace85044ef80f73cf9c214876a5aa4e77 (diff) | |
| download | rust-b59bd7fd16d6dfd3d09d1d708325d39763ec0ec7.tar.gz rust-b59bd7fd16d6dfd3d09d1d708325d39763ec0ec7.zip | |
review comments: clean up
| -rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 137 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/method/suggest.rs | 189 |
2 files changed, 166 insertions, 160 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 0ca7a8bb47b..612f645d5d5 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -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 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. + 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() { - 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 - }); + 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 diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 2196daa9878..ae40cb29ed6 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -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, |
