Skip to content

Commit 2a0b534

Browse files
authored
Rollup merge of #154939 - chenyukang:yukang-refactor-fn-pointer-cast-suggestion, r=davidtwco
Refactor: simplify report_selection_error Split out `suggest_cast_to_fn_pointer` for better readability.
2 parents 7d1b042 + 270cc62 commit 2a0b534

File tree

2 files changed

+66
-48
lines changed

2 files changed

+66
-48
lines changed

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_followed_by(span, ".").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: 58 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,
@@ -1142,6 +1143,62 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11421143
true
11431144
}
11441145

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

0 commit comments

Comments
 (0)