about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-01-11 20:22:00 -0800
committerMichael Goulet <michael@errs.io>2022-01-14 20:30:32 -0800
commitdae6dc6b97bcc7675b28f956d8aff2e27ede1a4f (patch)
tree4e45fc6a4273fd21f07292862a335501d2ec0c63
parentde9b573eedaaa6d6e7c00c986cccbee802f9287b (diff)
downloadrust-dae6dc6b97bcc7675b28f956d8aff2e27ede1a4f.tar.gz
rust-dae6dc6b97bcc7675b28f956d8aff2e27ede1a4f.zip
Fix `try wrapping expression in variant` suggestion with struct field shorthand
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs87
-rw-r--r--src/test/ui/did_you_mean/compatible-variants.rs8
-rw-r--r--src/test/ui/did_you_mean/compatible-variants.stderr31
3 files changed, 92 insertions, 34 deletions
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index c351a9f7040..4898109fa38 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -338,31 +338,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 })
                 .collect();
 
-            if let [variant] = &compatible_variants[..] {
-                // Just a single matching variant.
-                err.multipart_suggestion(
-                    &format!("try wrapping the expression in `{}`", variant),
-                    vec![
-                        (expr.span.shrink_to_lo(), format!("{}(", variant)),
-                        (expr.span.shrink_to_hi(), ")".to_string()),
-                    ],
-                    Applicability::MaybeIncorrect,
-                );
-            } else if compatible_variants.len() > 1 {
-                // More than one matching variant.
-                err.multipart_suggestions(
-                    &format!(
-                        "try wrapping the expression in a variant of `{}`",
-                        self.tcx.def_path_str(expected_adt.did)
-                    ),
-                    compatible_variants.into_iter().map(|variant| {
-                        vec![
-                            (expr.span.shrink_to_lo(), format!("{}(", variant)),
-                            (expr.span.shrink_to_hi(), ")".to_string()),
-                        ]
-                    }),
-                    Applicability::MaybeIncorrect,
-                );
+            if self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span) {
+                if let Ok(code) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
+                    match &compatible_variants[..] {
+                        [] => { /* No variants to format */ }
+                        [variant] => {
+                            // Just a single matching variant.
+                            err.span_suggestion_verbose(
+                                expr.span,
+                                &format!("try wrapping the expression in `{}`", variant),
+                                format!("{}: {}({})", code, variant, code),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                        _ => {
+                            // More than one matching variant.
+                            err.span_suggestions(
+                                expr.span,
+                                &format!(
+                                    "try wrapping the expression in a variant of `{}`",
+                                    self.tcx.def_path_str(expected_adt.did)
+                                ),
+                                compatible_variants
+                                    .into_iter()
+                                    .map(|variant| format!("{}: {}({})", code, variant, code)),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                    }
+                } else {
+                    /* Can't format this without a snippet */
+                }
+            } else {
+                match &compatible_variants[..] {
+                    [] => { /* No variants to format */ }
+                    [variant] => {
+                        // Just a single matching variant.
+                        err.multipart_suggestion_verbose(
+                            &format!("try wrapping the expression in `{}`", variant),
+                            vec![
+                                (expr.span.shrink_to_lo(), format!("{}(", variant)),
+                                (expr.span.shrink_to_hi(), ")".to_string()),
+                            ],
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    _ => {
+                        // More than one matching variant.
+                        err.multipart_suggestions(
+                            &format!(
+                                "try wrapping the expression in a variant of `{}`",
+                                self.tcx.def_path_str(expected_adt.did)
+                            ),
+                            compatible_variants.into_iter().map(|variant| {
+                                vec![
+                                    (expr.span.shrink_to_lo(), format!("{}(", variant)),
+                                    (expr.span.shrink_to_hi(), ")".to_string()),
+                                ]
+                            }),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
             }
         }
     }
diff --git a/src/test/ui/did_you_mean/compatible-variants.rs b/src/test/ui/did_you_mean/compatible-variants.rs
index fb6b6a5673d..a70dda8386f 100644
--- a/src/test/ui/did_you_mean/compatible-variants.rs
+++ b/src/test/ui/did_you_mean/compatible-variants.rs
@@ -3,6 +3,10 @@ enum Hey<A, B> {
     B(B),
 }
 
+struct Foo {
+    bar: Option<i32>,
+}
+
 fn f() {}
 
 fn a() -> Option<()> {
@@ -40,4 +44,8 @@ fn main() {
     let _: Hey<i32, bool> = false;
     //~^ ERROR mismatched types
     //~| HELP try wrapping
+    let bar = 1i32;
+    let _ = Foo { bar };
+    //~^ ERROR mismatched types
+    //~| HELP try wrapping
 }
diff --git a/src/test/ui/did_you_mean/compatible-variants.stderr b/src/test/ui/did_you_mean/compatible-variants.stderr
index e77949687fc..1d4448764c1 100644
--- a/src/test/ui/did_you_mean/compatible-variants.stderr
+++ b/src/test/ui/did_you_mean/compatible-variants.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/compatible-variants.rs:9:5
+  --> $DIR/compatible-variants.rs:13:5
    |
 LL |   fn a() -> Option<()> {
    |             ---------- expected `Option<()>` because of return type
@@ -21,7 +21,7 @@ LL +     Some(())
    |
 
 error[E0308]: mismatched types
-  --> $DIR/compatible-variants.rs:17:5
+  --> $DIR/compatible-variants.rs:21:5
    |
 LL | fn b() -> Result<(), ()> {
    |           -------------- expected `Result<(), ()>` because of return type
@@ -37,7 +37,7 @@ LL +     Ok(())
    |
 
 error[E0308]: mismatched types
-  --> $DIR/compatible-variants.rs:23:25
+  --> $DIR/compatible-variants.rs:27:25
    |
 LL |     let _: Option<()> = while false {};
    |            ----------   ^^^^^^^^^^^^^^ expected enum `Option`, found `()`
@@ -52,7 +52,7 @@ LL |     let _: Option<()> = Some(while false {});
    |                         +++++              +
 
 error[E0308]: mismatched types
-  --> $DIR/compatible-variants.rs:27:9
+  --> $DIR/compatible-variants.rs:31:9
    |
 LL |         while false {}
    |         ^^^^^^^^^^^^^^ expected enum `Option`, found `()`
@@ -69,7 +69,7 @@ LL +         Some(())
    |
 
 error[E0308]: mismatched types
-  --> $DIR/compatible-variants.rs:31:31
+  --> $DIR/compatible-variants.rs:35:31
    |
 LL |     let _: Result<i32, i32> = 1;
    |            ----------------   ^ expected enum `Result`, found integer
@@ -86,7 +86,7 @@ LL |     let _: Result<i32, i32> = Err(1);
    |                               ++++ +
 
 error[E0308]: mismatched types
-  --> $DIR/compatible-variants.rs:34:26
+  --> $DIR/compatible-variants.rs:38:26
    |
 LL |     let _: Option<i32> = 1;
    |            -----------   ^ expected enum `Option`, found integer
@@ -101,7 +101,7 @@ LL |     let _: Option<i32> = Some(1);
    |                          +++++ +
 
 error[E0308]: mismatched types
-  --> $DIR/compatible-variants.rs:37:28
+  --> $DIR/compatible-variants.rs:41:28
    |
 LL |     let _: Hey<i32, i32> = 1;
    |            -------------   ^ expected enum `Hey`, found integer
@@ -118,7 +118,7 @@ LL |     let _: Hey<i32, i32> = Hey::B(1);
    |                            +++++++ +
 
 error[E0308]: mismatched types
-  --> $DIR/compatible-variants.rs:40:29
+  --> $DIR/compatible-variants.rs:44:29
    |
 LL |     let _: Hey<i32, bool> = false;
    |            --------------   ^^^^^ expected enum `Hey`, found `bool`
@@ -132,6 +132,19 @@ help: try wrapping the expression in `Hey::B`
 LL |     let _: Hey<i32, bool> = Hey::B(false);
    |                             +++++++     +
 
-error: aborting due to 8 previous errors
+error[E0308]: mismatched types
+  --> $DIR/compatible-variants.rs:48:19
+   |
+LL |     let _ = Foo { bar };
+   |                   ^^^ expected enum `Option`, found `i32`
+   |
+   = note: expected enum `Option<i32>`
+              found type `i32`
+help: try wrapping the expression in `Some`
+   |
+LL |     let _ = Foo { bar: Some(bar) };
+   |                   ~~~~~~~~~~~~~~
+
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0308`.