Skip to content

Commit c400d43

Browse files
committed
refactor: simplify fn pointer cast suggestion logic
1 parent 906ca7f commit c400d43

2 files changed

Lines changed: 67 additions & 48 deletions

File tree

compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

Lines changed: 8 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,7 @@ use rustc_span::{BytePos, DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym};
3939
use tracing::{debug, instrument};
4040

4141
use super::suggestions::get_explanation_based_on_obligation;
42-
use super::{
43-
ArgKind, CandidateSimilarity, FindExprBySpan, GetSafeTransmuteErrorAndReason, ImplCandidate,
44-
};
42+
use super::{ArgKind, CandidateSimilarity, GetSafeTransmuteErrorAndReason, ImplCandidate};
4543
use crate::error_reporting::TypeErrCtxt;
4644
use crate::error_reporting::infer::TyCategory;
4745
use crate::error_reporting::traits::report_dyn_incompatibility;
@@ -452,50 +450,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
452450
self.suggest_dereferencing_index(&obligation, &mut err, leaf_trait_predicate);
453451
suggested |= self.suggest_dereferences(&obligation, &mut err, leaf_trait_predicate);
454452
suggested |= self.suggest_fn_call(&obligation, &mut err, leaf_trait_predicate);
455-
let impl_candidates = self.find_similar_impl_candidates(leaf_trait_predicate);
456-
suggested = if let &[cand] = &impl_candidates[..] {
457-
let cand = cand.trait_ref;
458-
if let (ty::FnPtr(..), ty::FnDef(..)) =
459-
(cand.self_ty().kind(), main_trait_predicate.self_ty().skip_binder().kind())
460-
{
461-
// Wrap method receivers and `&`-references in parens
462-
let suggestion = if self.tcx.sess.source_map().span_look_ahead(span, ".", Some(50)).is_some() {
463-
vec![
464-
(span.shrink_to_lo(), format!("(")),
465-
(span.shrink_to_hi(), format!(" as {})", cand.self_ty())),
466-
]
467-
} else if let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) {
468-
let mut expr_finder = FindExprBySpan::new(span, self.tcx);
469-
expr_finder.visit_expr(body.value);
470-
if let Some(expr) = expr_finder.result &&
471-
let hir::ExprKind::AddrOf(_, _, expr) = expr.kind {
472-
vec![
473-
(expr.span.shrink_to_lo(), format!("(")),
474-
(expr.span.shrink_to_hi(), format!(" as {})", cand.self_ty())),
475-
]
476-
} else {
477-
vec![(span.shrink_to_hi(), format!(" as {}", cand.self_ty()))]
478-
}
479-
} else {
480-
vec![(span.shrink_to_hi(), format!(" as {}", cand.self_ty()))]
481-
};
482-
let trait_ = self.tcx.short_string(cand.print_trait_sugared(), err.long_ty_path());
483-
let ty = self.tcx.short_string(cand.self_ty(), err.long_ty_path());
484-
err.multipart_suggestion(
485-
format!(
486-
"the trait `{trait_}` is implemented for fn pointer \
487-
`{ty}`, try casting using `as`",
488-
),
489-
suggestion,
490-
Applicability::MaybeIncorrect,
491-
);
492-
true
493-
} else {
494-
false
495-
}
496-
} else {
497-
false
498-
} || suggested;
453+
suggested |= self.suggest_cast_to_fn_pointer(
454+
&obligation,
455+
&mut err,
456+
leaf_trait_predicate,
457+
main_trait_predicate,
458+
span,
459+
);
499460
suggested |=
500461
self.suggest_remove_reference(&obligation, &mut err, leaf_trait_predicate);
501462
suggested |= self.suggest_semicolon_removal(

compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ use rustc_middle::ty::adjustment::{Adjust, DerefAdjustKind};
2929
use rustc_middle::ty::error::TypeError;
3030
use rustc_middle::ty::print::{
3131
PrintPolyTraitPredicateExt as _, PrintPolyTraitRefExt, PrintTraitPredicateExt as _,
32-
with_forced_trimmed_paths, with_no_trimmed_paths, with_types_for_suggestion,
32+
PrintTraitRefExt as _, with_forced_trimmed_paths, with_no_trimmed_paths,
33+
with_types_for_suggestion,
3334
};
3435
use rustc_middle::ty::{
3536
self, AdtKind, GenericArgs, InferTy, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeFolder,
@@ -1138,6 +1139,63 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11381139
true
11391140
}
11401141

1142+
pub(super) fn suggest_cast_to_fn_pointer(
1143+
&self,
1144+
obligation: &PredicateObligation<'tcx>,
1145+
err: &mut Diag<'_>,
1146+
leaf_trait_predicate: ty::PolyTraitPredicate<'tcx>,
1147+
main_trait_predicate: ty::PolyTraitPredicate<'tcx>,
1148+
span: Span,
1149+
) -> bool {
1150+
let &[candidate] = &self.find_similar_impl_candidates(leaf_trait_predicate)[..] else {
1151+
return false;
1152+
};
1153+
let candidate = candidate.trait_ref;
1154+
1155+
if !matches!(
1156+
(candidate.self_ty().kind(), main_trait_predicate.self_ty().skip_binder().kind(),),
1157+
(ty::FnPtr(..), ty::FnDef(..))
1158+
) {
1159+
return false;
1160+
}
1161+
1162+
let parenthesized_cast = |span: Span| {
1163+
vec![
1164+
(span.shrink_to_lo(), "(".to_string()),
1165+
(span.shrink_to_hi(), format!(" as {})", candidate.self_ty())),
1166+
]
1167+
};
1168+
// Wrap method receivers and `&`-references in parens.
1169+
let suggestion =
1170+
if self.tcx.sess.source_map().span_look_ahead(span, ".", Some(50)).is_some() {
1171+
parenthesized_cast(span)
1172+
} else if let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) {
1173+
let mut expr_finder = FindExprBySpan::new(span, self.tcx);
1174+
expr_finder.visit_expr(body.value);
1175+
if let Some(expr) = expr_finder.result
1176+
&& let hir::ExprKind::AddrOf(_, _, expr) = expr.kind
1177+
{
1178+
parenthesized_cast(expr.span)
1179+
} else {
1180+
vec![(span.shrink_to_hi(), format!(" as {}", candidate.self_ty()))]
1181+
}
1182+
} else {
1183+
vec![(span.shrink_to_hi(), format!(" as {}", candidate.self_ty()))]
1184+
};
1185+
1186+
let trait_ = self.tcx.short_string(candidate.print_trait_sugared(), err.long_ty_path());
1187+
let self_ty = self.tcx.short_string(candidate.self_ty(), err.long_ty_path());
1188+
err.multipart_suggestion(
1189+
format!(
1190+
"the trait `{trait_}` is implemented for fn pointer \
1191+
`{self_ty}`, try casting using `as`",
1192+
),
1193+
suggestion,
1194+
Applicability::MaybeIncorrect,
1195+
);
1196+
true
1197+
}
1198+
11411199
pub(super) fn check_for_binding_assigned_block_without_tail_expression(
11421200
&self,
11431201
obligation: &PredicateObligation<'tcx>,

0 commit comments

Comments
 (0)