about summary refs log tree commit diff
diff options
context:
space:
mode:
authorclubby789 <jamie@hill-daniel.co.uk>2023-07-25 11:23:11 +0000
committerclubby789 <jamie@hill-daniel.co.uk>2023-07-25 13:19:27 +0000
commitc83dfe9aedf79942e3416749b00803e0b5dcb5f2 (patch)
tree3531c326acaab2197ce4d022750d304559dafabe
parentff8fe76c0e36b65c038a080a8a8341024104d117 (diff)
downloadrust-c83dfe9aedf79942e3416749b00803e0b5dcb5f2.tar.gz
rust-c83dfe9aedf79942e3416749b00803e0b5dcb5f2.zip
Suggest `{Option,Result}::as_ref()` instead of `cloned()` in some cases
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs19
-rw-r--r--tests/ui/associated-types/dont-suggest-cyclic-constraint.fixed13
-rw-r--r--tests/ui/associated-types/dont-suggest-cyclic-constraint.rs4
-rw-r--r--tests/ui/associated-types/dont-suggest-cyclic-constraint.stderr6
-rw-r--r--tests/ui/suggestions/copied-and-cloned.fixed8
-rw-r--r--tests/ui/suggestions/copied-and-cloned.rs8
-rw-r--r--tests/ui/suggestions/copied-and-cloned.stderr15
8 files changed, 67 insertions, 8 deletions
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 45085534f72..26fa3d80d55 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 ec19d017c25..acea5f8c1f6 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 00000000000..ec4165cc71e
--- /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<I: Iterator>(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 6894f6b6cc4..0b4df08783d 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<I: Iterator>(mut iter: I, value: &I::Item)
+pub fn foo<I: Iterator>(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 3ecac9c83e5..c06c506a311 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<<I as Iterator>::Item>`, found `Option<&<I as Iterator>::Item>`
    |
    = note: expected enum `Option<<I as Iterator>::Item>`
               found enum `Option<&<I as Iterator>::Item>`
+help: use `Option::as_ref()` to convert `Option<<I as Iterator>::Item>` to `Option<&<I as Iterator>::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 f801403feec..13031f424cb 100644
--- a/tests/ui/suggestions/copied-and-cloned.fixed
+++ b/tests/ui/suggestions/copied-and-cloned.fixed
@@ -20,4 +20,12 @@ fn main() {
     expect::<Result<String, ()>>(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<String>` to `Option<&String>`
+
 }
diff --git a/tests/ui/suggestions/copied-and-cloned.rs b/tests/ui/suggestions/copied-and-cloned.rs
index 640450b7655..2927d66dea9 100644
--- a/tests/ui/suggestions/copied-and-cloned.rs
+++ b/tests/ui/suggestions/copied-and-cloned.rs
@@ -20,4 +20,12 @@ fn main() {
     expect::<Result<String, ()>>(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<String>` to `Option<&String>`
+
 }
diff --git a/tests/ui/suggestions/copied-and-cloned.stderr b/tests/ui/suggestions/copied-and-cloned.stderr
index 06780814182..19aaf6e00b1 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::<Result<String, ()>>(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<String>`, found `Option<&String>`
+   |
+   = note: expected enum `Option<String>`
+              found enum `Option<&String>`
+help: use `Option::as_ref()` to convert `Option<String>` 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`.