Skip to content

Commit b59bd7f

Browse files
committed
review comments: clean up
1 parent f566867 commit b59bd7f

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
@@ -1358,94 +1358,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13581358
// ...or if we already suggested that name because of `rustc_confusable` annotation.
13591359
&& Some(similar_candidate.name) != confusable_suggested
13601360
{
1361-
let def_kind = similar_candidate.kind.as_def_kind();
1362-
let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
1363-
// Methods are defined within the context of a struct and their first parameter
1364-
// is always `self`, which represents the instance of the struct the method is
1365-
// being called on Associated functions don’t take self as a parameter and they are
1366-
// not methods because they don’t have an instance of the struct to work with.
1367-
if def_kind == DefKind::AssocFn {
1368-
let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
1369-
let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
1370-
let fn_sig =
1371-
self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig);
1372-
if similar_candidate.fn_has_self_parameter {
1373-
if let Some(args) = args
1374-
&& fn_sig.inputs()[1..].len() == args.len()
1375-
{
1376-
// We found a method with the same number of arguments as the method
1377-
// call expression the user wrote.
1378-
err.span_suggestion_verbose(
1379-
span,
1380-
format!("there is {an} method with a similar name"),
1381-
similar_candidate.name,
1382-
Applicability::MaybeIncorrect,
1383-
);
1384-
} else {
1385-
// We found a method but either the expression is not a method call or
1386-
// the argument count didn't match.
1387-
err.span_help(
1388-
tcx.def_span(similar_candidate.def_id),
1389-
format!(
1390-
"there is {an} method `{}` with a similar name{}",
1391-
similar_candidate.name,
1392-
if let None = args {
1393-
""
1394-
} else {
1395-
", but with different arguments"
1396-
},
1397-
),
1398-
);
1399-
}
1400-
} else if let Some(args) = args
1401-
&& fn_sig.inputs().len() == args.len()
1402-
{
1403-
// We have fn call expression and the argument count match the associated
1404-
// function we found.
1405-
err.span_suggestion_verbose(
1406-
span,
1407-
format!(
1408-
"there is {an} {} with a similar name",
1409-
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
1410-
),
1411-
similar_candidate.name,
1412-
Applicability::MaybeIncorrect,
1413-
);
1414-
} else {
1415-
err.span_help(
1416-
tcx.def_span(similar_candidate.def_id),
1417-
format!(
1418-
"there is {an} {} `{}` with a similar name",
1419-
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
1420-
similar_candidate.name,
1421-
),
1422-
);
1423-
}
1424-
} else if let Mode::Path = mode
1425-
&& args.unwrap_or(&[]).is_empty()
1426-
{
1427-
// We have an associated item syntax and we found something that isn't an fn.
1428-
err.span_suggestion_verbose(
1429-
span,
1430-
format!(
1431-
"there is {an} {} with a similar name",
1432-
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
1433-
),
1434-
similar_candidate.name,
1435-
Applicability::MaybeIncorrect,
1436-
);
1437-
} else {
1438-
// The expression is a function or method call, but the item we found is an
1439-
// associated const or type.
1440-
err.span_help(
1441-
tcx.def_span(similar_candidate.def_id),
1442-
format!(
1443-
"there is {an} {} `{}` with a similar name",
1444-
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
1445-
similar_candidate.name,
1446-
),
1447-
);
1448-
}
1361+
self.find_likely_intended_associated_item(
1362+
&mut err,
1363+
similar_candidate,
1364+
span,
1365+
args,
1366+
mode,
1367+
);
14491368
}
14501369
}
14511370
// If an appropriate error source is not found, check method chain for possible candiates
@@ -1497,6 +1416,100 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14971416
Some(err)
14981417
}
14991418

1419+
fn find_likely_intended_associated_item(
1420+
&self,
1421+
err: &mut Diagnostic,
1422+
similar_candidate: ty::AssocItem,
1423+
span: Span,
1424+
args: Option<&'tcx [hir::Expr<'tcx>]>,
1425+
mode: Mode,
1426+
) {
1427+
let tcx = self.tcx;
1428+
let def_kind = similar_candidate.kind.as_def_kind();
1429+
let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
1430+
// Methods are defined within the context of a struct and their first parameter
1431+
// is always `self`, which represents the instance of the struct the method is
1432+
// being called on Associated functions don’t take self as a parameter and they are
1433+
// not methods because they don’t have an instance of the struct to work with.
1434+
if def_kind == DefKind::AssocFn {
1435+
let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
1436+
let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
1437+
let fn_sig = self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig);
1438+
if similar_candidate.fn_has_self_parameter {
1439+
if let Some(args) = args
1440+
&& fn_sig.inputs()[1..].len() == args.len()
1441+
{
1442+
// We found a method with the same number of arguments as the method
1443+
// call expression the user wrote.
1444+
err.span_suggestion_verbose(
1445+
span,
1446+
format!("there is {an} method with a similar name"),
1447+
similar_candidate.name,
1448+
Applicability::MaybeIncorrect,
1449+
);
1450+
} else {
1451+
// We found a method but either the expression is not a method call or
1452+
// the argument count didn't match.
1453+
err.span_help(
1454+
tcx.def_span(similar_candidate.def_id),
1455+
format!(
1456+
"there is {an} method `{}` with a similar name{}",
1457+
similar_candidate.name,
1458+
if let None = args { "" } else { ", but with different arguments" },
1459+
),
1460+
);
1461+
}
1462+
} else if let Some(args) = args
1463+
&& fn_sig.inputs().len() == args.len()
1464+
{
1465+
// We have fn call expression and the argument count match the associated
1466+
// function we found.
1467+
err.span_suggestion_verbose(
1468+
span,
1469+
format!(
1470+
"there is {an} {} with a similar name",
1471+
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
1472+
),
1473+
similar_candidate.name,
1474+
Applicability::MaybeIncorrect,
1475+
);
1476+
} else {
1477+
err.span_help(
1478+
tcx.def_span(similar_candidate.def_id),
1479+
format!(
1480+
"there is {an} {} `{}` with a similar name",
1481+
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
1482+
similar_candidate.name,
1483+
),
1484+
);
1485+
}
1486+
} else if let Mode::Path = mode
1487+
&& args.unwrap_or(&[]).is_empty()
1488+
{
1489+
// We have an associated item syntax and we found something that isn't an fn.
1490+
err.span_suggestion_verbose(
1491+
span,
1492+
format!(
1493+
"there is {an} {} with a similar name",
1494+
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
1495+
),
1496+
similar_candidate.name,
1497+
Applicability::MaybeIncorrect,
1498+
);
1499+
} else {
1500+
// The expression is a function or method call, but the item we found is an
1501+
// associated const or type.
1502+
err.span_help(
1503+
tcx.def_span(similar_candidate.def_id),
1504+
format!(
1505+
"there is {an} {} `{}` with a similar name",
1506+
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
1507+
similar_candidate.name,
1508+
),
1509+
);
1510+
}
1511+
}
1512+
15001513
pub(crate) fn confusable_method_name(
15011514
&self,
15021515
err: &mut Diagnostic,

0 commit comments

Comments
 (0)