From c83dfe9aedf79942e3416749b00803e0b5dcb5f2 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Tue, 25 Jul 2023 11:23:11 +0000 Subject: [PATCH] Suggest `{Option,Result}::as_ref()` instead of `cloned()` in some cases --- compiler/rustc_hir_typeck/src/demand.rs | 2 +- .../src/fn_ctxt/suggestions.rs | 19 +++++++++++++++---- .../dont-suggest-cyclic-constraint.fixed | 13 +++++++++++++ .../dont-suggest-cyclic-constraint.rs | 4 +++- .../dont-suggest-cyclic-constraint.stderr | 6 +++++- tests/ui/suggestions/copied-and-cloned.fixed | 8 ++++++++ tests/ui/suggestions/copied-and-cloned.rs | 8 ++++++++ tests/ui/suggestions/copied-and-cloned.stderr | 15 ++++++++++++++- 8 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 tests/ui/associated-types/dont-suggest-cyclic-constraint.fixed diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 45085534f72fb..26fa3d80d553f 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -53,7 +53,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_no_capture_closure(err, expected, expr_ty) || self.suggest_boxing_when_appropriate(err, expr.span, expr.hir_id, expected, expr_ty) || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected) - || self.suggest_copied_or_cloned(err, expr, expr_ty, expected) + || self.suggest_copied_cloned_or_as_ref(err, expr, expr_ty, expected, expected_ty_expr) || self.suggest_clone_for_ref(err, expr, expr_ty, expected) || self.suggest_into(err, expr, expr_ty, expected) || self.suggest_floating_point_literal(err, expr, expected) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index ec19d017c259b..acea5f8c1f63f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1085,12 +1085,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } - pub(crate) fn suggest_copied_or_cloned( + pub(crate) fn suggest_copied_cloned_or_as_ref( &self, diag: &mut Diagnostic, expr: &hir::Expr<'_>, expr_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, + expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, ) -> bool { let ty::Adt(adt_def, args) = expr_ty.kind() else { return false; @@ -1102,7 +1103,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } - let mut suggest_copied_or_cloned = || { + let mut suggest_copied_cloned_or_as_ref = || { let expr_inner_ty = args.type_at(0); let expected_inner_ty = expected_args.type_at(0); if let &ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind() @@ -1119,6 +1120,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); return true; + } else if let Some(expected_ty_expr) = expected_ty_expr { + diag.span_suggestion_verbose( + expected_ty_expr.span.shrink_to_hi(), + format!( + "use `{def_path}::as_ref()` to convert `{expected_ty}` to `{expr_ty}`" + ), + ".as_ref()", + Applicability::MachineApplicable, + ); + return true; } else if let Some(clone_did) = self.tcx.lang_items().clone_trait() && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions( self, @@ -1146,11 +1157,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Check that the error types are equal && self.can_eq(self.param_env, args.type_at(1), expected_args.type_at(1)) { - return suggest_copied_or_cloned(); + return suggest_copied_cloned_or_as_ref(); } else if let Some(option_did) = self.tcx.get_diagnostic_item(sym::Option) && adt_def.did() == option_did { - return suggest_copied_or_cloned(); + return suggest_copied_cloned_or_as_ref(); } false diff --git a/tests/ui/associated-types/dont-suggest-cyclic-constraint.fixed b/tests/ui/associated-types/dont-suggest-cyclic-constraint.fixed new file mode 100644 index 0000000000000..ec4165cc71e28 --- /dev/null +++ b/tests/ui/associated-types/dont-suggest-cyclic-constraint.fixed @@ -0,0 +1,13 @@ +// run-rustfix + +use std::fmt::Debug; + +pub fn foo(mut iter: I, value: &I::Item) +where + I::Item: Eq + Debug, +{ + debug_assert_eq!(iter.next().as_ref(), Some(value)); + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/associated-types/dont-suggest-cyclic-constraint.rs b/tests/ui/associated-types/dont-suggest-cyclic-constraint.rs index 6894f6b6cc4a0..0b4df08783d63 100644 --- a/tests/ui/associated-types/dont-suggest-cyclic-constraint.rs +++ b/tests/ui/associated-types/dont-suggest-cyclic-constraint.rs @@ -1,6 +1,8 @@ +// run-rustfix + use std::fmt::Debug; -fn foo(mut iter: I, value: &I::Item) +pub fn foo(mut iter: I, value: &I::Item) where I::Item: Eq + Debug, { diff --git a/tests/ui/associated-types/dont-suggest-cyclic-constraint.stderr b/tests/ui/associated-types/dont-suggest-cyclic-constraint.stderr index 3ecac9c83e571..c06c506a311a8 100644 --- a/tests/ui/associated-types/dont-suggest-cyclic-constraint.stderr +++ b/tests/ui/associated-types/dont-suggest-cyclic-constraint.stderr @@ -1,11 +1,15 @@ error[E0308]: mismatched types - --> $DIR/dont-suggest-cyclic-constraint.rs:7:35 + --> $DIR/dont-suggest-cyclic-constraint.rs:9:35 | LL | debug_assert_eq!(iter.next(), Some(value)); | ^^^^^^^^^^^ expected `Option<::Item>`, found `Option<&::Item>` | = note: expected enum `Option<::Item>` found enum `Option<&::Item>` +help: use `Option::as_ref()` to convert `Option<::Item>` to `Option<&::Item>` + | +LL | debug_assert_eq!(iter.next().as_ref(), Some(value)); + | +++++++++ error: aborting due to previous error diff --git a/tests/ui/suggestions/copied-and-cloned.fixed b/tests/ui/suggestions/copied-and-cloned.fixed index f801403feec4f..13031f424cbe7 100644 --- a/tests/ui/suggestions/copied-and-cloned.fixed +++ b/tests/ui/suggestions/copied-and-cloned.fixed @@ -20,4 +20,12 @@ fn main() { expect::>(x.cloned()); //~^ ERROR mismatched types //~| HELP use `Result::cloned` to clone the value inside the `Result` + + let s = String::new(); + let x = Some(s.clone()); + let y = Some(&s); + println!("{}", x.as_ref() == y); + //~^ ERROR mismatched types + //~| HELP use `Option::as_ref()` to convert `Option` to `Option<&String>` + } diff --git a/tests/ui/suggestions/copied-and-cloned.rs b/tests/ui/suggestions/copied-and-cloned.rs index 640450b765527..2927d66dea94e 100644 --- a/tests/ui/suggestions/copied-and-cloned.rs +++ b/tests/ui/suggestions/copied-and-cloned.rs @@ -20,4 +20,12 @@ fn main() { expect::>(x); //~^ ERROR mismatched types //~| HELP use `Result::cloned` to clone the value inside the `Result` + + let s = String::new(); + let x = Some(s.clone()); + let y = Some(&s); + println!("{}", x == y); + //~^ ERROR mismatched types + //~| HELP use `Option::as_ref()` to convert `Option` to `Option<&String>` + } diff --git a/tests/ui/suggestions/copied-and-cloned.stderr b/tests/ui/suggestions/copied-and-cloned.stderr index 0678081418248..19aaf6e00b133 100644 --- a/tests/ui/suggestions/copied-and-cloned.stderr +++ b/tests/ui/suggestions/copied-and-cloned.stderr @@ -78,6 +78,19 @@ help: use `Result::cloned` to clone the value inside the `Result` LL | expect::>(x.cloned()); | +++++++++ -error: aborting due to 4 previous errors +error[E0308]: mismatched types + --> $DIR/copied-and-cloned.rs:27:25 + | +LL | println!("{}", x == y); + | ^ expected `Option`, found `Option<&String>` + | + = note: expected enum `Option` + found enum `Option<&String>` +help: use `Option::as_ref()` to convert `Option` to `Option<&String>` + | +LL | println!("{}", x.as_ref() == y); + | +++++++++ + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0308`.