1
Fork 0

Rollup merge of #101367 - compiler-errors:suggest-copied-or-cloned, r=lcnr

Suggest `{Option,Result}::{copied,clone}()` to satisfy type mismatch

Fixes #100699, but in the opposite direction (instead of suggesting to fix the signature, it fixes the body)
This commit is contained in:
Dylan DPC 2022-09-05 14:15:51 +05:30 committed by GitHub
commit d18dc3d2ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 194 additions and 0 deletions

View file

@ -42,6 +42,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
self.suggest_missing_parentheses(err, expr);
self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected);
self.suggest_copied_or_cloned(err, expr, expr_ty, expected);
self.note_type_is_not_clone(err, expected, expr_ty, expr);
self.note_need_for_fn_pointer(err, expected, expr_ty);
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);

View file

@ -17,6 +17,7 @@ use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty};
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@ -925,6 +926,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
pub(crate) fn suggest_copied_or_cloned(
&self,
diag: &mut Diagnostic,
expr: &hir::Expr<'_>,
expr_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>,
) {
let ty::Adt(adt_def, substs) = expr_ty.kind() else { return; };
let ty::Adt(expected_adt_def, expected_substs) = expected_ty.kind() else { return; };
if adt_def != expected_adt_def {
return;
}
let mut suggest_copied_or_cloned = || {
let expr_inner_ty = substs.type_at(0);
let expected_inner_ty = expected_substs.type_at(0);
if let ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind()
&& self.can_eq(self.param_env, *ty, expected_inner_ty).is_ok()
{
let def_path = self.tcx.def_path_str(adt_def.did());
if self.type_is_copy_modulo_regions(self.param_env, *ty, expr.span) {
diag.span_suggestion_verbose(
expr.span.shrink_to_hi(),
format!(
"use `{def_path}::copied` to copy the value inside the `{def_path}`"
),
".copied()",
Applicability::MachineApplicable,
);
} else if let Some(clone_did) = self.tcx.lang_items().clone_trait()
&& rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions(
self,
self.param_env,
*ty,
clone_did,
expr.span
)
{
diag.span_suggestion_verbose(
expr.span.shrink_to_hi(),
format!(
"use `{def_path}::cloned` to clone the value inside the `{def_path}`"
),
".cloned()",
Applicability::MachineApplicable,
);
}
}
};
if let Some(result_did) = self.tcx.get_diagnostic_item(sym::Result)
&& adt_def.did() == result_did
// Check that the error types are equal
&& self.can_eq(self.param_env, substs.type_at(1), expected_substs.type_at(1)).is_ok()
{
suggest_copied_or_cloned();
} else if let Some(option_did) = self.tcx.get_diagnostic_item(sym::Option)
&& adt_def.did() == option_did
{
suggest_copied_or_cloned();
}
}
/// Suggest wrapping the block in square brackets instead of curly braces
/// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
pub(crate) fn suggest_block_to_brackets(