mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
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.
This commit is contained in:
@@ -39,9 +39,7 @@
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::suggestions::get_explanation_based_on_obligation;
|
||||
use super::{
|
||||
ArgKind, CandidateSimilarity, FindExprBySpan, GetSafeTransmuteErrorAndReason, ImplCandidate,
|
||||
};
|
||||
use super::{ArgKind, CandidateSimilarity, GetSafeTransmuteErrorAndReason, ImplCandidate};
|
||||
use crate::error_reporting::TypeErrCtxt;
|
||||
use crate::error_reporting::infer::TyCategory;
|
||||
use crate::error_reporting::traits::report_dyn_incompatibility;
|
||||
@@ -452,50 +450,13 @@ pub fn report_selection_error(
|
||||
self.suggest_dereferencing_index(&obligation, &mut err, leaf_trait_predicate);
|
||||
suggested |= self.suggest_dereferences(&obligation, &mut err, leaf_trait_predicate);
|
||||
suggested |= self.suggest_fn_call(&obligation, &mut err, leaf_trait_predicate);
|
||||
let impl_candidates = self.find_similar_impl_candidates(leaf_trait_predicate);
|
||||
suggested = if let &[cand] = &impl_candidates[..] {
|
||||
let cand = cand.trait_ref;
|
||||
if let (ty::FnPtr(..), ty::FnDef(..)) =
|
||||
(cand.self_ty().kind(), main_trait_predicate.self_ty().skip_binder().kind())
|
||||
{
|
||||
// Wrap method receivers and `&`-references in parens
|
||||
let suggestion = if self.tcx.sess.source_map().span_followed_by(span, ".").is_some() {
|
||||
vec![
|
||||
(span.shrink_to_lo(), format!("(")),
|
||||
(span.shrink_to_hi(), format!(" as {})", cand.self_ty())),
|
||||
]
|
||||
} else if let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) {
|
||||
let mut expr_finder = FindExprBySpan::new(span, self.tcx);
|
||||
expr_finder.visit_expr(body.value);
|
||||
if let Some(expr) = expr_finder.result &&
|
||||
let hir::ExprKind::AddrOf(_, _, expr) = expr.kind {
|
||||
vec![
|
||||
(expr.span.shrink_to_lo(), format!("(")),
|
||||
(expr.span.shrink_to_hi(), format!(" as {})", cand.self_ty())),
|
||||
]
|
||||
} else {
|
||||
vec![(span.shrink_to_hi(), format!(" as {}", cand.self_ty()))]
|
||||
}
|
||||
} else {
|
||||
vec![(span.shrink_to_hi(), format!(" as {}", cand.self_ty()))]
|
||||
};
|
||||
let trait_ = self.tcx.short_string(cand.print_trait_sugared(), err.long_ty_path());
|
||||
let ty = self.tcx.short_string(cand.self_ty(), err.long_ty_path());
|
||||
err.multipart_suggestion(
|
||||
format!(
|
||||
"the trait `{trait_}` is implemented for fn pointer \
|
||||
`{ty}`, try casting using `as`",
|
||||
),
|
||||
suggestion,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
} || suggested;
|
||||
suggested |= self.suggest_cast_to_fn_pointer(
|
||||
&obligation,
|
||||
&mut err,
|
||||
leaf_trait_predicate,
|
||||
main_trait_predicate,
|
||||
span,
|
||||
);
|
||||
suggested |=
|
||||
self.suggest_remove_reference(&obligation, &mut err, leaf_trait_predicate);
|
||||
suggested |= self.suggest_semicolon_removal(
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::print::{
|
||||
PrintPolyTraitPredicateExt as _, PrintPolyTraitRefExt, PrintTraitPredicateExt as _,
|
||||
with_forced_trimmed_paths, with_no_trimmed_paths, with_types_for_suggestion,
|
||||
PrintTraitRefExt as _, with_forced_trimmed_paths, with_no_trimmed_paths,
|
||||
with_types_for_suggestion,
|
||||
};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtKind, GenericArgs, InferTy, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeFolder,
|
||||
@@ -1142,6 +1143,62 @@ pub(super) fn suggest_fn_call(
|
||||
true
|
||||
}
|
||||
|
||||
pub(super) fn suggest_cast_to_fn_pointer(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut Diag<'_>,
|
||||
leaf_trait_predicate: ty::PolyTraitPredicate<'tcx>,
|
||||
main_trait_predicate: ty::PolyTraitPredicate<'tcx>,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
let &[candidate] = &self.find_similar_impl_candidates(leaf_trait_predicate)[..] else {
|
||||
return false;
|
||||
};
|
||||
let candidate = candidate.trait_ref;
|
||||
|
||||
if !matches!(
|
||||
(candidate.self_ty().kind(), main_trait_predicate.self_ty().skip_binder().kind(),),
|
||||
(ty::FnPtr(..), ty::FnDef(..))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let parenthesized_cast = |span: Span| {
|
||||
vec![
|
||||
(span.shrink_to_lo(), "(".to_string()),
|
||||
(span.shrink_to_hi(), format!(" as {})", candidate.self_ty())),
|
||||
]
|
||||
};
|
||||
// Wrap method receivers and `&`-references in parens.
|
||||
let suggestion = if self.tcx.sess.source_map().span_followed_by(span, ".").is_some() {
|
||||
parenthesized_cast(span)
|
||||
} else if let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) {
|
||||
let mut expr_finder = FindExprBySpan::new(span, self.tcx);
|
||||
expr_finder.visit_expr(body.value);
|
||||
if let Some(expr) = expr_finder.result
|
||||
&& let hir::ExprKind::AddrOf(_, _, expr) = expr.kind
|
||||
{
|
||||
parenthesized_cast(expr.span)
|
||||
} else {
|
||||
vec![(span.shrink_to_hi(), format!(" as {}", candidate.self_ty()))]
|
||||
}
|
||||
} else {
|
||||
vec![(span.shrink_to_hi(), format!(" as {}", candidate.self_ty()))]
|
||||
};
|
||||
|
||||
let trait_ = self.tcx.short_string(candidate.print_trait_sugared(), err.long_ty_path());
|
||||
let self_ty = self.tcx.short_string(candidate.self_ty(), err.long_ty_path());
|
||||
err.multipart_suggestion(
|
||||
format!(
|
||||
"the trait `{trait_}` is implemented for fn pointer \
|
||||
`{self_ty}`, try casting using `as`",
|
||||
),
|
||||
suggestion,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
true
|
||||
}
|
||||
|
||||
pub(super) fn check_for_binding_assigned_block_without_tail_expression(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
|
||||
Reference in New Issue
Block a user