Skip to content

Commit 997351d

Browse files
committed
review comments: clean up
1 parent b49aa7c commit 997351d

File tree

2 files changed

+166
-160
lines changed

2 files changed

+166
-160
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

Lines changed: 65 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -563,80 +563,73 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
563563
};
564564

565565
let suggest_confusable = |err: &mut Diagnostic| {
566-
if let Some(call_name) = call_ident
567-
&& let Some(callee_ty) = callee_ty
566+
let call_name = call_ident?;
567+
let callee_ty = callee_ty?;
568+
let input_types: Vec<Ty<'_>> = provided_arg_tys.iter().map(|(ty, _)| *ty).collect();
569+
// Check for other methods in the following order
570+
// - methods marked as `rustc_confusables` with the provided arguments
571+
// - methods with the same argument type/count and short levenshtein distance
572+
// - methods marked as `rustc_confusables` (done)
573+
// - methods with short levenshtein distance
574+
575+
// Look for commonly confusable method names considering arguments.
576+
if let Some(name) = self.confusable_method_name(
577+
err,
578+
callee_ty.peel_refs(),
579+
call_name,
580+
Some(input_types.clone()),
581+
) {
582+
return Some(name);
583+
}
584+
// Look for method names with short levenshtein distance, considering arguments.
585+
if let Some((assoc, fn_sig)) = similar_assoc(call_name)
586+
&& fn_sig.inputs()[1..]
587+
.iter()
588+
.zip(input_types.iter())
589+
.all(|(expected, found)| self.can_coerce(*expected, *found))
590+
&& fn_sig.inputs()[1..].len() == input_types.len()
568591
{
569-
let input_types: Vec<Ty<'_>> = provided_arg_tys.iter().map(|(ty, _)| *ty).collect();
570-
// Check for other methods in the following order
571-
// - methods marked as `rustc_confusables` with the provided arguments
572-
// - methods with the same argument type/count and short levenshtein distance
573-
// - methods marked as `rustc_confusables` (done)
574-
// - methods with short levenshtein distance
575-
576-
// Look for commonly confusable method names considering arguments.
577-
self.confusable_method_name(
578-
err,
579-
callee_ty.peel_refs(),
580-
call_name,
581-
Some(input_types.clone()),
582-
)
583-
.or_else(|| {
584-
// Look for method names with short levenshtein distance, considering arguments.
585-
if let Some((assoc, fn_sig)) = similar_assoc(call_name)
586-
&& fn_sig.inputs()[1..]
587-
.iter()
588-
.zip(input_types.iter())
589-
.all(|(expected, found)| self.can_coerce(*expected, *found))
590-
&& fn_sig.inputs()[1..].len() == input_types.len()
591-
{
592-
err.span_suggestion_verbose(
593-
call_name.span,
594-
format!("you might have meant to use `{}`", assoc.name),
595-
assoc.name,
596-
Applicability::MaybeIncorrect,
597-
);
598-
return Some(assoc.name);
599-
}
600-
None
601-
})
602-
.or_else(|| {
603-
// Look for commonly confusable method names disregarding arguments.
604-
self.confusable_method_name(err, callee_ty.peel_refs(), call_name, None)
605-
})
606-
.or_else(|| {
607-
// Look for similarly named methods with levenshtein distance with the right
608-
// number of arguments.
609-
if let Some((assoc, fn_sig)) = similar_assoc(call_name)
610-
&& fn_sig.inputs()[1..].len() == input_types.len()
611-
{
612-
err.span_note(
613-
tcx.def_span(assoc.def_id),
614-
format!(
615-
"there's is a method with similar name `{}`, but the arguments \
616-
don't match",
617-
assoc.name,
618-
),
619-
);
620-
return Some(assoc.name);
621-
}
622-
None
623-
})
624-
.or_else(|| {
625-
// Fallthrough: look for similarly named methods with levenshtein distance.
626-
if let Some((assoc, _)) = similar_assoc(call_name) {
627-
err.span_note(
628-
tcx.def_span(assoc.def_id),
629-
format!(
630-
"there's is a method with similar name `{}`, but their argument \
631-
count doesn't match",
632-
assoc.name,
633-
),
634-
);
635-
return Some(assoc.name);
636-
}
637-
None
638-
});
592+
err.span_suggestion_verbose(
593+
call_name.span,
594+
format!("you might have meant to use `{}`", assoc.name),
595+
assoc.name,
596+
Applicability::MaybeIncorrect,
597+
);
598+
return Some(assoc.name);
599+
}
600+
// Look for commonly confusable method names disregarding arguments.
601+
if let Some(name) =
602+
self.confusable_method_name(err, callee_ty.peel_refs(), call_name, None)
603+
{
604+
return Some(name);
605+
}
606+
// Look for similarly named methods with levenshtein distance with the right
607+
// number of arguments.
608+
if let Some((assoc, fn_sig)) = similar_assoc(call_name)
609+
&& fn_sig.inputs()[1..].len() == input_types.len()
610+
{
611+
err.span_note(
612+
tcx.def_span(assoc.def_id),
613+
format!(
614+
"there's is a method with similar name `{}`, but the arguments don't match",
615+
assoc.name,
616+
),
617+
);
618+
return Some(assoc.name);
639619
}
620+
// Fallthrough: look for similarly named methods with levenshtein distance.
621+
if let Some((assoc, _)) = similar_assoc(call_name) {
622+
err.span_note(
623+
tcx.def_span(assoc.def_id),
624+
format!(
625+
"there's is a method with similar name `{}`, but their argument count \
626+
doesn't match",
627+
assoc.name,
628+
),
629+
);
630+
return Some(assoc.name);
631+
}
632+
None
640633
};
641634
// A "softer" version of the `demand_compatible`, which checks types without persisting them,
642635
// and treats error types differently

compiler/rustc_hir_typeck/src/method/suggest.rs

Lines changed: 101 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,94 +1256,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12561256
// ...or if we already suggested that name because of `rustc_confusable` annotation.
12571257
&& Some(similar_candidate.name) != confusable_suggested
12581258
{
1259-
let def_kind = similar_candidate.kind.as_def_kind();
1260-
let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
1261-
// Methods are defined within the context of a struct and their first parameter
1262-
// is always `self`, which represents the instance of the struct the method is
1263-
// being called on Associated functions don’t take self as a parameter and they are
1264-
// not methods because they don’t have an instance of the struct to work with.
1265-
if def_kind == DefKind::AssocFn {
1266-
let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
1267-
let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
1268-
let fn_sig =
1269-
self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig);
1270-
if similar_candidate.fn_has_self_parameter {
1271-
if let Some(args) = args
1272-
&& fn_sig.inputs()[1..].len() == args.len()
1273-
{
1274-
// We found a method with the same number of arguments as the method
1275-
// call expression the user wrote.
1276-
err.span_suggestion_verbose(
1277-
span,
1278-
format!("there is {an} method with a similar name"),
1279-
similar_candidate.name,
1280-
Applicability::MaybeIncorrect,
1281-
);
1282-
} else {
1283-
// We found a method but either the expression is not a method call or
1284-
// the argument count didn't match.
1285-
err.span_help(
1286-
tcx.def_span(similar_candidate.def_id),
1287-
format!(
1288-
"there is {an} method `{}` with a similar name{}",
1289-
similar_candidate.name,
1290-
if let None = args {
1291-
""
1292-
} else {
1293-
", but with different arguments"
1294-
},
1295-
),
1296-
);
1297-
}
1298-
} else if let Some(args) = args
1299-
&& fn_sig.inputs().len() == args.len()
1300-
{
1301-
// We have fn call expression and the argument count match the associated
1302-
// function we found.
1303-
err.span_suggestion_verbose(
1304-
span,
1305-
format!(
1306-
"there is {an} {} with a similar name",
1307-
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
1308-
),
1309-
similar_candidate.name,
1310-
Applicability::MaybeIncorrect,
1311-
);
1312-
} else {
1313-
err.span_help(
1314-
tcx.def_span(similar_candidate.def_id),
1315-
format!(
1316-
"there is {an} {} `{}` with a similar name",
1317-
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
1318-
similar_candidate.name,
1319-
),
1320-
);
1321-
}
1322-
} else if let Mode::Path = mode
1323-
&& args.unwrap_or(&[]).is_empty()
1324-
{
1325-
// We have an associated item syntax and we found something that isn't an fn.
1326-
err.span_suggestion_verbose(
1327-
span,
1328-
format!(
1329-
"there is {an} {} with a similar name",
1330-
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
1331-
),
1332-
similar_candidate.name,
1333-
Applicability::MaybeIncorrect,
1334-
);
1335-
} else {
1336-
// The expression is a function or method call, but the item we found is an
1337-
// associated const or type.
1338-
err.span_help(
1339-
tcx.def_span(similar_candidate.def_id),
1340-
format!(
1341-
"there is {an} {} `{}` with a similar name",
1342-
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
1343-
similar_candidate.name,
1344-
),
1345-
);
1346-
}
1259+
self.find_likely_intended_associated_item(
1260+
&mut err,
1261+
similar_candidate,
1262+
span,
1263+
args,
1264+
mode,
1265+
);
13471266
}
13481267
}
13491268
// If an appropriate error source is not found, check method chain for possible candiates
@@ -1395,6 +1314,100 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13951314
Some(err)
13961315
}
13971316

1317+
fn find_likely_intended_associated_item(
1318+
&self,
1319+
err: &mut Diagnostic,
1320+
similar_candidate: ty::AssocItem,
1321+
span: Span,
1322+
args: Option<&'tcx [hir::Expr<'tcx>]>,
1323+
mode: Mode,
1324+
) {
1325+
let tcx = self.tcx;
1326+
let def_kind = similar_candidate.kind.as_def_kind();
1327+
let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
1328+
// Methods are defined within the context of a struct and their first parameter
1329+
// is always `self`, which represents the instance of the struct the method is
1330+
// being called on Associated functions don’t take self as a parameter and they are
1331+
// not methods because they don’t have an instance of the struct to work with.
1332+
if def_kind == DefKind::AssocFn {
1333+
let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
1334+
let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
1335+
let fn_sig = self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig);
1336+
if similar_candidate.fn_has_self_parameter {
1337+
if let Some(args) = args
1338+
&& fn_sig.inputs()[1..].len() == args.len()
1339+
{
1340+
// We found a method with the same number of arguments as the method
1341+
// call expression the user wrote.
1342+
err.span_suggestion_verbose(
1343+
span,
1344+
format!("there is {an} method with a similar name"),
1345+
similar_candidate.name,
1346+
Applicability::MaybeIncorrect,
1347+
);
1348+
} else {
1349+
// We found a method but either the expression is not a method call or
1350+
// the argument count didn't match.
1351+
err.span_help(
1352+
tcx.def_span(similar_candidate.def_id),
1353+
format!(
1354+
"there is {an} method `{}` with a similar name{}",
1355+
similar_candidate.name,
1356+
if let None = args { "" } else { ", but with different arguments" },
1357+
),
1358+
);
1359+
}
1360+
} else if let Some(args) = args
1361+
&& fn_sig.inputs().len() == args.len()
1362+
{
1363+
// We have fn call expression and the argument count match the associated
1364+
// function we found.
1365+
err.span_suggestion_verbose(
1366+
span,
1367+
format!(
1368+
"there is {an} {} with a similar name",
1369+
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
1370+
),
1371+
similar_candidate.name,
1372+
Applicability::MaybeIncorrect,
1373+
);
1374+
} else {
1375+
err.span_help(
1376+
tcx.def_span(similar_candidate.def_id),
1377+
format!(
1378+
"there is {an} {} `{}` with a similar name",
1379+
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
1380+
similar_candidate.name,
1381+
),
1382+
);
1383+
}
1384+
} else if let Mode::Path = mode
1385+
&& args.unwrap_or(&[]).is_empty()
1386+
{
1387+
// We have an associated item syntax and we found something that isn't an fn.
1388+
err.span_suggestion_verbose(
1389+
span,
1390+
format!(
1391+
"there is {an} {} with a similar name",
1392+
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
1393+
),
1394+
similar_candidate.name,
1395+
Applicability::MaybeIncorrect,
1396+
);
1397+
} else {
1398+
// The expression is a function or method call, but the item we found is an
1399+
// associated const or type.
1400+
err.span_help(
1401+
tcx.def_span(similar_candidate.def_id),
1402+
format!(
1403+
"there is {an} {} `{}` with a similar name",
1404+
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
1405+
similar_candidate.name,
1406+
),
1407+
);
1408+
}
1409+
}
1410+
13981411
pub(crate) fn confusable_method_name(
13991412
&self,
14001413
err: &mut Diagnostic,

0 commit comments

Comments
 (0)