Suggest copied or cloned
This commit is contained in:
parent
0209485578
commit
fdbede7ad8
@ -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);
|
||||
|
@ -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(
|
||||
|
23
src/test/ui/suggestions/copied-and-cloned.fixed
Normal file
23
src/test/ui/suggestions/copied-and-cloned.fixed
Normal file
@ -0,0 +1,23 @@
|
||||
// run-rustfix
|
||||
|
||||
fn expect<T>(_: T) {}
|
||||
|
||||
fn main() {
|
||||
let x = Some(&());
|
||||
expect::<Option<()>>(x.copied());
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP use `Option::copied` to copy the value inside the `Option`
|
||||
let x = Ok(&());
|
||||
expect::<Result<(), ()>>(x.copied());
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP use `Result::copied` to copy the value inside the `Result`
|
||||
let s = String::new();
|
||||
let x = Some(&s);
|
||||
expect::<Option<String>>(x.cloned());
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP use `Option::cloned` to clone the value inside the `Option`
|
||||
let x = Ok(&s);
|
||||
expect::<Result<String, ()>>(x.cloned());
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP use `Result::cloned` to clone the value inside the `Result`
|
||||
}
|
23
src/test/ui/suggestions/copied-and-cloned.rs
Normal file
23
src/test/ui/suggestions/copied-and-cloned.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// run-rustfix
|
||||
|
||||
fn expect<T>(_: T) {}
|
||||
|
||||
fn main() {
|
||||
let x = Some(&());
|
||||
expect::<Option<()>>(x);
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP use `Option::copied` to copy the value inside the `Option`
|
||||
let x = Ok(&());
|
||||
expect::<Result<(), ()>>(x);
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP use `Result::copied` to copy the value inside the `Result`
|
||||
let s = String::new();
|
||||
let x = Some(&s);
|
||||
expect::<Option<String>>(x);
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP use `Option::cloned` to clone the value inside the `Option`
|
||||
let x = Ok(&s);
|
||||
expect::<Result<String, ()>>(x);
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP use `Result::cloned` to clone the value inside the `Result`
|
||||
}
|
83
src/test/ui/suggestions/copied-and-cloned.stderr
Normal file
83
src/test/ui/suggestions/copied-and-cloned.stderr
Normal file
@ -0,0 +1,83 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/copied-and-cloned.rs:7:26
|
||||
|
|
||||
LL | expect::<Option<()>>(x);
|
||||
| -------------------- ^ expected `()`, found `&()`
|
||||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
= note: expected enum `Option<()>`
|
||||
found enum `Option<&()>`
|
||||
note: function defined here
|
||||
--> $DIR/copied-and-cloned.rs:3:4
|
||||
|
|
||||
LL | fn expect<T>(_: T) {}
|
||||
| ^^^^^^ ----
|
||||
help: use `Option::copied` to copy the value inside the `Option`
|
||||
|
|
||||
LL | expect::<Option<()>>(x.copied());
|
||||
| +++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/copied-and-cloned.rs:11:30
|
||||
|
|
||||
LL | expect::<Result<(), ()>>(x);
|
||||
| ------------------------ ^ expected `()`, found `&()`
|
||||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
= note: expected enum `Result<(), ()>`
|
||||
found enum `Result<&(), _>`
|
||||
note: function defined here
|
||||
--> $DIR/copied-and-cloned.rs:3:4
|
||||
|
|
||||
LL | fn expect<T>(_: T) {}
|
||||
| ^^^^^^ ----
|
||||
help: use `Result::copied` to copy the value inside the `Result`
|
||||
|
|
||||
LL | expect::<Result<(), ()>>(x.copied());
|
||||
| +++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/copied-and-cloned.rs:16:30
|
||||
|
|
||||
LL | expect::<Option<String>>(x);
|
||||
| ------------------------ ^ expected struct `String`, found `&String`
|
||||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
= note: expected enum `Option<String>`
|
||||
found enum `Option<&String>`
|
||||
note: function defined here
|
||||
--> $DIR/copied-and-cloned.rs:3:4
|
||||
|
|
||||
LL | fn expect<T>(_: T) {}
|
||||
| ^^^^^^ ----
|
||||
help: use `Option::cloned` to clone the value inside the `Option`
|
||||
|
|
||||
LL | expect::<Option<String>>(x.cloned());
|
||||
| +++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/copied-and-cloned.rs:20:34
|
||||
|
|
||||
LL | expect::<Result<String, ()>>(x);
|
||||
| ---------------------------- ^ expected struct `String`, found `&String`
|
||||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
= note: expected enum `Result<String, ()>`
|
||||
found enum `Result<&String, _>`
|
||||
note: function defined here
|
||||
--> $DIR/copied-and-cloned.rs:3:4
|
||||
|
|
||||
LL | fn expect<T>(_: T) {}
|
||||
| ^^^^^^ ----
|
||||
help: use `Result::cloned` to clone the value inside the `Result`
|
||||
|
|
||||
LL | expect::<Result<String, ()>>(x.cloned());
|
||||
| +++++++++
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
Loading…
x
Reference in New Issue
Block a user