mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Migrate SuggestAsRefWhereAppropriate
This commit is contained in:
parent
37f55691f4
commit
b36abea285
@ -353,3 +353,10 @@ infer_fps_use_ref = consider using a reference
|
|||||||
infer_fps_remove_ref = consider removing the reference
|
infer_fps_remove_ref = consider removing the reference
|
||||||
infer_fps_cast = consider casting to a fn pointer
|
infer_fps_cast = consider casting to a fn pointer
|
||||||
infer_fps_items_are_distinct = fn items are distinct from fn pointers
|
infer_fps_items_are_distinct = fn items are distinct from fn pointers
|
||||||
|
infer_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}`
|
||||||
|
|
||||||
|
infer_fn_uniq_types = different fn items have unique types, even if their signatures are the same
|
||||||
|
infer_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}`
|
||||||
|
|
||||||
|
infer_sarwa_option = you can convert from `&Option<T>` to `Option<&T>` using `.as_ref()`
|
||||||
|
infer_sarwa_result = you can convert from `&Result<T, E>` to `Result<&T, &E>` using `.as_ref()`
|
||||||
|
@ -1158,6 +1158,14 @@ pub struct OpaqueCapturesLifetime<'tcx> {
|
|||||||
pub opaque_ty: Ty<'tcx>,
|
pub opaque_ty: Ty<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct DiagArg<T>(pub T);
|
||||||
|
|
||||||
|
impl<T: ToString> IntoDiagnosticArg for DiagArg<T> {
|
||||||
|
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
|
||||||
|
self.0.to_string().into_diagnostic_arg()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub enum FunctionPointerSuggestion<'a> {
|
pub enum FunctionPointerSuggestion<'a> {
|
||||||
#[suggestion(
|
#[suggestion(
|
||||||
@ -1212,8 +1220,72 @@ pub enum FunctionPointerSuggestion<'a> {
|
|||||||
#[skip_arg]
|
#[skip_arg]
|
||||||
sig: Binder<'a, FnSig<'a>>,
|
sig: Binder<'a, FnSig<'a>>,
|
||||||
},
|
},
|
||||||
|
#[suggestion(
|
||||||
|
infer_fps_cast_both,
|
||||||
|
code = "{fn_name} as {found_sig}",
|
||||||
|
style = "hidden",
|
||||||
|
applicability = "maybe-incorrect"
|
||||||
|
)]
|
||||||
|
CastBoth {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
#[skip_arg]
|
||||||
|
fn_name: String,
|
||||||
|
#[skip_arg]
|
||||||
|
found_sig: Binder<'a, FnSig<'a>>,
|
||||||
|
expected_sig: DiagArg<Binder<'a, FnSig<'a>>>,
|
||||||
|
},
|
||||||
|
#[suggestion(
|
||||||
|
infer_fps_cast_both,
|
||||||
|
code = "&({fn_name} as {found_sig})",
|
||||||
|
style = "hidden",
|
||||||
|
applicability = "maybe-incorrect"
|
||||||
|
)]
|
||||||
|
CastBothRef {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
#[skip_arg]
|
||||||
|
fn_name: String,
|
||||||
|
#[skip_arg]
|
||||||
|
found_sig: Binder<'a, FnSig<'a>>,
|
||||||
|
expected_sig: DiagArg<Binder<'a, FnSig<'a>>>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[note(infer_fps_items_are_distinct)]
|
#[note(infer_fps_items_are_distinct)]
|
||||||
pub struct FnItemsAreDistinct;
|
pub struct FnItemsAreDistinct;
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[note(infer_fn_uniq_types)]
|
||||||
|
pub struct FnUniqTypes;
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[help(infer_fn_uniq_types)]
|
||||||
|
pub struct FnConsiderCasting {
|
||||||
|
pub casting: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
pub enum SuggestAsRefWhereAppropriate<'a> {
|
||||||
|
#[suggestion(
|
||||||
|
infer_sarwa_option,
|
||||||
|
code = "{snippet}.as_ref()",
|
||||||
|
applicability = "machine-applicable"
|
||||||
|
)]
|
||||||
|
Option {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
snippet: &'a str,
|
||||||
|
},
|
||||||
|
#[suggestion(
|
||||||
|
infer_sarwa_result,
|
||||||
|
code = "{snippet}.as_ref()",
|
||||||
|
applicability = "machine-applicable"
|
||||||
|
)]
|
||||||
|
Result {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
snippet: &'a str,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@ -13,12 +13,19 @@ use rustc_span::{sym, BytePos, Span};
|
|||||||
use rustc_target::abi::FieldIdx;
|
use rustc_target::abi::FieldIdx;
|
||||||
|
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
ConsiderAddingAwait, FnItemsAreDistinct, FunctionPointerSuggestion, SuggAddLetForLetChains,
|
ConsiderAddingAwait, DiagArg, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes,
|
||||||
|
FunctionPointerSuggestion, SuggAddLetForLetChains, SuggestAsRefWhereAppropriate,
|
||||||
SuggestRemoveSemiOrReturnBinding,
|
SuggestRemoveSemiOrReturnBinding,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::TypeErrCtxt;
|
use super::TypeErrCtxt;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum SuggestAsRefKind {
|
||||||
|
Option,
|
||||||
|
Result,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
pub(super) fn suggest_remove_semi_or_return_binding(
|
pub(super) fn suggest_remove_semi_or_return_binding(
|
||||||
&self,
|
&self,
|
||||||
@ -322,15 +329,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
diag: &mut Diagnostic,
|
diag: &mut Diagnostic,
|
||||||
) {
|
) {
|
||||||
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
|
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
|
||||||
&& let Some(msg) = self.should_suggest_as_ref(exp_found.expected, exp_found.found)
|
&& let Some(msg) = self.should_suggest_as_ref_kind(exp_found.expected, exp_found.found)
|
||||||
{
|
{
|
||||||
diag.span_suggestion(
|
|
||||||
span,
|
|
||||||
msg,
|
|
||||||
// HACK: fix issue# 100605, suggesting convert from &Option<T> to Option<&T>, remove the extra `&`
|
// HACK: fix issue# 100605, suggesting convert from &Option<T> to Option<&T>, remove the extra `&`
|
||||||
format!("{}.as_ref()", snippet.trim_start_matches('&')),
|
let snippet = snippet.trim_start_matches('&');
|
||||||
Applicability::MachineApplicable,
|
let subdiag = match msg {
|
||||||
);
|
SuggestAsRefKind::Option => SuggestAsRefWhereAppropriate::Option { span, snippet },
|
||||||
|
SuggestAsRefKind::Result => SuggestAsRefWhereAppropriate::Result { span, snippet },
|
||||||
|
};
|
||||||
|
diag.subdiagnostic(subdiag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,7 +391,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
&(self.normalize_fn_sig)(self.tcx.fn_sig(*did2).subst(self.tcx, substs2));
|
&(self.normalize_fn_sig)(self.tcx.fn_sig(*did2).subst(self.tcx, substs2));
|
||||||
|
|
||||||
if self.same_type_modulo_infer(*expected_sig, *found_sig) {
|
if self.same_type_modulo_infer(*expected_sig, *found_sig) {
|
||||||
diag.note("different fn items have unique types, even if their signatures are the same");
|
diag.subdiagnostic(FnUniqTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.same_type_modulo_infer(*found_sig, *expected_sig)
|
if !self.same_type_modulo_infer(*found_sig, *expected_sig)
|
||||||
@ -398,16 +405,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
|
|
||||||
let fn_name = self.tcx.def_path_str_with_substs(*did2, substs2);
|
let fn_name = self.tcx.def_path_str_with_substs(*did2, substs2);
|
||||||
let sug = if found.is_ref() {
|
let sug = if found.is_ref() {
|
||||||
format!("&({fn_name} as {found_sig})")
|
FunctionPointerSuggestion::CastBothRef {
|
||||||
|
span,
|
||||||
|
fn_name,
|
||||||
|
found_sig: *found_sig,
|
||||||
|
expected_sig: DiagArg(*expected_sig),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
format!("{fn_name} as {found_sig}")
|
FunctionPointerSuggestion::CastBoth {
|
||||||
|
span,
|
||||||
|
fn_name,
|
||||||
|
found_sig: *found_sig,
|
||||||
|
expected_sig: DiagArg(*expected_sig),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let msg = format!(
|
diag.subdiagnostic(sug);
|
||||||
"consider casting both fn items to fn pointers using `as {expected_sig}`"
|
|
||||||
);
|
|
||||||
|
|
||||||
diag.span_suggestion_hidden(span, msg, sug, Applicability::MaybeIncorrect);
|
|
||||||
}
|
}
|
||||||
(ty::FnDef(did, substs), ty::FnPtr(sig)) => {
|
(ty::FnDef(did, substs), ty::FnPtr(sig)) => {
|
||||||
let expected_sig =
|
let expected_sig =
|
||||||
@ -426,7 +439,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
format!("{fn_name} as {found_sig}")
|
format!("{fn_name} as {found_sig}")
|
||||||
};
|
};
|
||||||
|
|
||||||
diag.help(&format!("consider casting the fn item to a fn pointer: `{}`", casting));
|
diag.subdiagnostic(FnConsiderCasting { casting });
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return;
|
return;
|
||||||
@ -434,23 +447,19 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn should_suggest_as_ref(&self, expected: Ty<'tcx>, found: Ty<'tcx>) -> Option<&str> {
|
pub fn should_suggest_as_ref_kind(
|
||||||
|
&self,
|
||||||
|
expected: Ty<'tcx>,
|
||||||
|
found: Ty<'tcx>,
|
||||||
|
) -> Option<SuggestAsRefKind> {
|
||||||
if let (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) =
|
if let (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) =
|
||||||
(expected.kind(), found.kind())
|
(expected.kind(), found.kind())
|
||||||
{
|
{
|
||||||
if let ty::Adt(found_def, found_substs) = *found_ty.kind() {
|
if let ty::Adt(found_def, found_substs) = *found_ty.kind() {
|
||||||
if exp_def == &found_def {
|
if exp_def == &found_def {
|
||||||
let have_as_ref = &[
|
let have_as_ref = &[
|
||||||
(
|
(sym::Option, SuggestAsRefKind::Option),
|
||||||
sym::Option,
|
(sym::Result, SuggestAsRefKind::Result),
|
||||||
"you can convert from `&Option<T>` to `Option<&T>` using \
|
|
||||||
`.as_ref()`",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
sym::Result,
|
|
||||||
"you can convert from `&Result<T, E>` to \
|
|
||||||
`Result<&T, &E>` using `.as_ref()`",
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
if let Some(msg) = have_as_ref.iter().find_map(|(name, msg)| {
|
if let Some(msg) = have_as_ref.iter().find_map(|(name, msg)| {
|
||||||
self.tcx.is_diagnostic_item(*name, exp_def.did()).then_some(msg)
|
self.tcx.is_diagnostic_item(*name, exp_def.did()).then_some(msg)
|
||||||
@ -484,6 +493,20 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Remove once rustc_hir_typeck is migrated to Diagnostics
|
||||||
|
pub fn should_suggest_as_ref(&self, expected: Ty<'tcx>, found: Ty<'tcx>) -> Option<&str> {
|
||||||
|
match self.should_suggest_as_ref_kind(expected, found) {
|
||||||
|
Some(SuggestAsRefKind::Option) => Some(
|
||||||
|
"you can convert from `&Option<T>` to `Option<&T>` using \
|
||||||
|
`.as_ref()`",
|
||||||
|
),
|
||||||
|
Some(SuggestAsRefKind::Result) => Some(
|
||||||
|
"you can convert from `&Result<T, E>` to \
|
||||||
|
`Result<&T, &E>` using `.as_ref()`",
|
||||||
|
),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
/// Try to find code with pattern `if Some(..) = expr`
|
/// Try to find code with pattern `if Some(..) = expr`
|
||||||
/// use a `visitor` to mark the `if` which its span contains given error span,
|
/// use a `visitor` to mark the `if` which its span contains given error span,
|
||||||
/// and then try to find a assignment in the `cond` part, which span is equal with error span
|
/// and then try to find a assignment in the `cond` part, which span is equal with error span
|
||||||
|
Loading…
Reference in New Issue
Block a user