about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs39
-rw-r--r--tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.fixed77
-rw-r--r--tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.rs77
-rw-r--r--tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.stderr80
5 files changed, 266 insertions, 9 deletions
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index aff1baa1960..74aec897f95 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -626,7 +626,7 @@ pub struct SuggestConvertViaMethod<'tcx> {
     pub span: Span,
     #[suggestion_part(code = "")]
     pub borrow_removal_span: Option<Span>,
-    pub sugg: &'static str,
+    pub sugg: String,
     pub expected: Ty<'tcx>,
     pub found: Ty<'tcx>,
 }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 2a072795a6c..a904b419a94 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -442,12 +442,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     expected,
                 )
             });
+
+            let prefix_wrap = |sugg: &str| {
+                if let Some(name) = self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
+                    format!(": {}{}", name, sugg)
+                } else {
+                    sugg.to_string()
+                }
+            };
+
             // FIXME: This could/should be extended to suggest `as_mut` and `as_deref_mut`,
             // but those checks need to be a bit more delicate and the benefit is diminishing.
             if self.can_eq(self.param_env, found_ty_inner, peeled) && error_tys_equate_as_ref {
+                let sugg = prefix_wrap(".as_ref()");
                 err.subdiagnostic(errors::SuggestConvertViaMethod {
                     span: expr.span.shrink_to_hi(),
-                    sugg: ".as_ref()",
+                    sugg,
                     expected,
                     found,
                     borrow_removal_span,
@@ -458,9 +468,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 && self.can_eq(self.param_env, deref_ty, peeled)
                 && error_tys_equate_as_ref
             {
+                let sugg = prefix_wrap(".as_deref()");
                 err.subdiagnostic(errors::SuggestConvertViaMethod {
                     span: expr.span.shrink_to_hi(),
-                    sugg: ".as_deref()",
+                    sugg,
                     expected,
                     found,
                     borrow_removal_span,
@@ -474,10 +485,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     self.can_eq(self.param_env, found, expected)
                 })
             {
+                let sugg = prefix_wrap(".map(|x| x.as_str())");
                 err.span_suggestion_verbose(
                     expr.span.shrink_to_hi(),
                     fluent::hir_typeck_convert_to_str,
-                    ".map(|x| x.as_str())",
+                    sugg,
                     Applicability::MachineApplicable,
                 );
                 return true;
@@ -628,12 +640,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             err.help("use `Box::pin`");
                         }
                         _ => {
+                            let prefix = if let Some(name) =
+                                self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr)
+                            {
+                                format!("{}: ", name)
+                            } else {
+                                String::new()
+                            };
+                            let suggestion = vec![
+                                (expr.span.shrink_to_lo(), format!("{prefix}Box::pin(")),
+                                (expr.span.shrink_to_hi(), ")".to_string()),
+                            ];
                             err.multipart_suggestion(
                                 "you need to pin and box this expression",
-                                vec![
-                                    (expr.span.shrink_to_lo(), "Box::pin(".to_string()),
-                                    (expr.span.shrink_to_hi(), ")".to_string()),
-                                ],
+                                suggestion,
                                 Applicability::MaybeIncorrect,
                             );
                         }
@@ -1214,7 +1234,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 span = parent_callsite;
             }
 
-            let sugg = if expr.precedence().order() >= PREC_POSTFIX {
+            let mut sugg = if expr.precedence().order() >= PREC_POSTFIX {
                 vec![(span.shrink_to_hi(), ".into()".to_owned())]
             } else {
                 vec![
@@ -1222,6 +1242,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     (span.shrink_to_hi(), ").into()".to_owned()),
                 ]
             };
+            if let Some(name) = self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
+                sugg.insert(0, (expr.span.shrink_to_lo(), format!("{}: ", name)));
+            }
             diag.multipart_suggestion(
                 format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),
                 sugg,
diff --git a/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.fixed b/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.fixed
new file mode 100644
index 00000000000..e1f929e6170
--- /dev/null
+++ b/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.fixed
@@ -0,0 +1,77 @@
+// run-rustfix
+// edition:2021
+#![allow(dead_code)]
+#![allow(unused_variables)]
+use std::future::Future;
+use std::pin::Pin;
+
+fn test1() {
+    let string = String::from("Hello, world");
+
+    struct Demo<'a> {
+        option: Option<&'a str>,
+    }
+
+    let option: Option<String> = Some(string.clone());
+    let s = Demo { option: option.as_deref() }; //~ ERROR mismatched types
+}
+
+fn test2() {
+    let string = String::from("Hello, world");
+
+    struct Demo<'a> {
+        option_ref: Option<&'a str>,
+    }
+
+    let option_ref = Some(&string);
+    let s = Demo { option_ref: option_ref.map(|x| x.as_str()) }; //~ ERROR mismatched types
+}
+
+fn test3() {
+    let string = String::from("Hello, world");
+
+    struct Demo<'a> {
+        option_ref_ref: Option<&'a str>,
+    }
+
+    let option_ref = Some(&string);
+    let option_ref_ref = option_ref.as_ref();
+
+    let s = Demo { option_ref_ref: option_ref_ref.map(|x| x.as_str()) }; //~ ERROR mismatched types
+}
+
+fn test4() {
+    let a = 1;
+    struct Demo {
+        a: String,
+    }
+    let s = Demo { a: a.to_string() }; //~ ERROR mismatched types
+}
+
+type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
+fn test5() {
+    let a = async { 42 };
+    struct Demo {
+        a: BoxFuture<'static, i32>,
+    }
+    let s = Demo { a: Box::pin(a) }; //~ ERROR mismatched types
+}
+
+fn test6() {
+    struct A;
+    struct B;
+
+    impl From<B> for A {
+        fn from(_: B) -> Self {
+            A
+        }
+    }
+
+    struct Demo {
+        a: A,
+    }
+    let a = B;
+    let s = Demo { a: a.into() }; //~ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.rs b/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.rs
new file mode 100644
index 00000000000..956936c925b
--- /dev/null
+++ b/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.rs
@@ -0,0 +1,77 @@
+// run-rustfix
+// edition:2021
+#![allow(dead_code)]
+#![allow(unused_variables)]
+use std::future::Future;
+use std::pin::Pin;
+
+fn test1() {
+    let string = String::from("Hello, world");
+
+    struct Demo<'a> {
+        option: Option<&'a str>,
+    }
+
+    let option: Option<String> = Some(string.clone());
+    let s = Demo { option }; //~ ERROR mismatched types
+}
+
+fn test2() {
+    let string = String::from("Hello, world");
+
+    struct Demo<'a> {
+        option_ref: Option<&'a str>,
+    }
+
+    let option_ref = Some(&string);
+    let s = Demo { option_ref }; //~ ERROR mismatched types
+}
+
+fn test3() {
+    let string = String::from("Hello, world");
+
+    struct Demo<'a> {
+        option_ref_ref: Option<&'a str>,
+    }
+
+    let option_ref = Some(&string);
+    let option_ref_ref = option_ref.as_ref();
+
+    let s = Demo { option_ref_ref }; //~ ERROR mismatched types
+}
+
+fn test4() {
+    let a = 1;
+    struct Demo {
+        a: String,
+    }
+    let s = Demo { a }; //~ ERROR mismatched types
+}
+
+type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
+fn test5() {
+    let a = async { 42 };
+    struct Demo {
+        a: BoxFuture<'static, i32>,
+    }
+    let s = Demo { a }; //~ ERROR mismatched types
+}
+
+fn test6() {
+    struct A;
+    struct B;
+
+    impl From<B> for A {
+        fn from(_: B) -> Self {
+            A
+        }
+    }
+
+    struct Demo {
+        a: A,
+    }
+    let a = B;
+    let s = Demo { a }; //~ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.stderr b/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.stderr
new file mode 100644
index 00000000000..1baf95d2bf7
--- /dev/null
+++ b/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.stderr
@@ -0,0 +1,80 @@
+error[E0308]: mismatched types
+  --> $DIR/mismatch-sugg-for-shorthand-field.rs:16:20
+   |
+LL |     let s = Demo { option };
+   |                    ^^^^^^ expected `Option<&str>`, found `Option<String>`
+   |
+   = note: expected enum `Option<&str>`
+              found enum `Option<String>`
+help: try using `: option.as_deref()` to convert `Option<String>` to `Option<&str>`
+   |
+LL |     let s = Demo { option: option.as_deref() };
+   |                          +++++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-sugg-for-shorthand-field.rs:27:20
+   |
+LL |     let s = Demo { option_ref };
+   |                    ^^^^^^^^^^ expected `Option<&str>`, found `Option<&String>`
+   |
+   = note: expected enum `Option<&str>`
+              found enum `Option<&String>`
+help: try converting the passed type into a `&str`
+   |
+LL |     let s = Demo { option_ref: option_ref.map(|x| x.as_str()) };
+   |                              ++++++++++++++++++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-sugg-for-shorthand-field.rs:40:20
+   |
+LL |     let s = Demo { option_ref_ref };
+   |                    ^^^^^^^^^^^^^^ expected `Option<&str>`, found `Option<&&String>`
+   |
+   = note: expected enum `Option<&str>`
+              found enum `Option<&&String>`
+help: try converting the passed type into a `&str`
+   |
+LL |     let s = Demo { option_ref_ref: option_ref_ref.map(|x| x.as_str()) };
+   |                                  ++++++++++++++++++++++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-sugg-for-shorthand-field.rs:48:20
+   |
+LL |     let s = Demo { a };
+   |                    ^ expected `String`, found integer
+   |
+help: try using a conversion method
+   |
+LL |     let s = Demo { a: a.to_string() };
+   |                    ++  ++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-sugg-for-shorthand-field.rs:57:20
+   |
+LL |     let a = async { 42 };
+   |             ------------ the found `async` block
+...
+LL |     let s = Demo { a };
+   |                    ^ expected `Pin<Box<...>>`, found `async` block
+   |
+   = note:     expected struct `Pin<Box<(dyn Future<Output = i32> + Send + 'static)>>`
+           found `async` block `{async block@$DIR/mismatch-sugg-for-shorthand-field.rs:53:13: 53:25}`
+help: you need to pin and box this expression
+   |
+LL |     let s = Demo { a: Box::pin(a) };
+   |                    ++++++++++++ +
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-sugg-for-shorthand-field.rs:74:20
+   |
+LL |     let s = Demo { a };
+   |                    ^ expected `A`, found `B`
+   |
+help: call `Into::into` on this expression to convert `B` into `A`
+   |
+LL |     let s = Demo { a: a.into() };
+   |                    ++  +++++++
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0308`.