about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs55
-rw-r--r--src/test/ui/structs/struct-record-suggestion.fixed24
-rw-r--r--src/test/ui/structs/struct-record-suggestion.rs24
-rw-r--r--src/test/ui/structs/struct-record-suggestion.stderr23
4 files changed, 96 insertions, 30 deletions
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 6e97b0bf2ab..a0fa27a1018 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1518,7 +1518,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut error_happened = false;
 
         // Type-check each field.
-        for field in ast_fields {
+        for (idx, field) in ast_fields.iter().enumerate() {
             let ident = tcx.adjust_ident(field.ident, variant.def_id);
             let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) {
                 seen_fields.insert(ident, field.span);
@@ -1556,7 +1556,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             // Make sure to give a type to the field even if there's
             // an error, so we can continue type-checking.
-            self.check_expr_coercable_to_type(&field.expr, field_type, None);
+            let ty = self.check_expr_with_hint(&field.expr, field_type);
+            let (_, diag) =
+                self.demand_coerce_diag(&field.expr, ty, field_type, None, AllowTwoPhase::No);
+
+            if let Some(mut diag) = diag {
+                if idx == ast_fields.len() - 1 && remaining_fields.is_empty() {
+                    self.suggest_fru_from_range(field, variant, substs, &mut diag);
+                }
+                diag.emit();
+            }
         }
 
         // Make sure the programmer specified correct number of fields.
@@ -1784,25 +1793,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         );
         err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}"));
 
-        // If the last field is a range literal, but it isn't supposed to be, then they probably
-        // meant to use functional update syntax.
-        //
+        if let Some(last) = ast_fields.last() {
+            self.suggest_fru_from_range(last, variant, substs, &mut err);
+        }
+
+        err.emit();
+    }
+
+    /// If the last field is a range literal, but it isn't supposed to be, then they probably
+    /// meant to use functional update syntax.
+    fn suggest_fru_from_range(
+        &self,
+        last_expr_field: &hir::ExprField<'tcx>,
+        variant: &ty::VariantDef,
+        substs: SubstsRef<'tcx>,
+        err: &mut Diagnostic,
+    ) {
         // I don't use 'is_range_literal' because only double-sided, half-open ranges count.
-        if let Some((
-            last,
-            ExprKind::Struct(
+        if let ExprKind::Struct(
                 QPath::LangItem(LangItem::Range, ..),
                 &[ref range_start, ref range_end],
                 _,
-            ),
-        )) = ast_fields.last().map(|last| (last, &last.expr.kind)) &&
-        let variant_field =
-            variant.fields.iter().find(|field| field.ident(self.tcx) == last.ident) &&
-        let range_def_id = self.tcx.lang_items().range_struct() &&
-        variant_field
-            .and_then(|field| field.ty(self.tcx, substs).ty_adt_def())
-            .map(|adt| adt.did())
-            != range_def_id
+            ) = last_expr_field.expr.kind
+            && let variant_field =
+                variant.fields.iter().find(|field| field.ident(self.tcx) == last_expr_field.ident)
+            && let range_def_id = self.tcx.lang_items().range_struct()
+            && variant_field
+                .and_then(|field| field.ty(self.tcx, substs).ty_adt_def())
+                .map(|adt| adt.did())
+                != range_def_id
         {
             let instead = self
                 .tcx
@@ -1818,8 +1837,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Applicability::MaybeIncorrect,
             );
         }
-
-        err.emit();
     }
 
     /// Report an error for a struct field expression when there are invisible fields.
diff --git a/src/test/ui/structs/struct-record-suggestion.fixed b/src/test/ui/structs/struct-record-suggestion.fixed
index 48144cd1ce2..49e38b196de 100644
--- a/src/test/ui/structs/struct-record-suggestion.fixed
+++ b/src/test/ui/structs/struct-record-suggestion.fixed
@@ -6,11 +6,29 @@ struct A {
     d: usize,
 }
 
-fn main() {
-    let q = A { c: 5, .. Default::default() };
+fn a() {
+    let q = A { c: 5,..Default::default() };
     //~^ ERROR mismatched types
     //~| ERROR missing fields
     //~| HELP separate the last named field with a comma
-    let r = A { c: 5, .. Default::default() };
+    let r = A { c: 5, ..Default::default() };
     assert_eq!(q, r);
 }
+
+#[derive(Debug, Default, Eq, PartialEq)]
+struct B {
+    b: u32,
+}
+
+fn b() {
+    let q = B { b: 1,..Default::default() };
+    //~^ ERROR mismatched types
+    //~| HELP separate the last named field with a comma
+    let r = B { b: 1 };
+    assert_eq!(q, r);
+}
+
+fn main() {
+    a();
+    b();
+}
diff --git a/src/test/ui/structs/struct-record-suggestion.rs b/src/test/ui/structs/struct-record-suggestion.rs
index 6d169d5c6db..901f310c8bd 100644
--- a/src/test/ui/structs/struct-record-suggestion.rs
+++ b/src/test/ui/structs/struct-record-suggestion.rs
@@ -6,11 +6,29 @@ struct A {
     d: usize,
 }
 
-fn main() {
-    let q = A { c: 5 .. Default::default() };
+fn a() {
+    let q = A { c: 5..Default::default() };
     //~^ ERROR mismatched types
     //~| ERROR missing fields
     //~| HELP separate the last named field with a comma
-    let r = A { c: 5, .. Default::default() };
+    let r = A { c: 5, ..Default::default() };
     assert_eq!(q, r);
 }
+
+#[derive(Debug, Default, Eq, PartialEq)]
+struct B {
+    b: u32,
+}
+
+fn b() {
+    let q = B { b: 1..Default::default() };
+    //~^ ERROR mismatched types
+    //~| HELP separate the last named field with a comma
+    let r = B { b: 1 };
+    assert_eq!(q, r);
+}
+
+fn main() {
+    a();
+    b();
+}
diff --git a/src/test/ui/structs/struct-record-suggestion.stderr b/src/test/ui/structs/struct-record-suggestion.stderr
index e5bd03117b9..66e9f021ed6 100644
--- a/src/test/ui/structs/struct-record-suggestion.stderr
+++ b/src/test/ui/structs/struct-record-suggestion.stderr
@@ -1,8 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/struct-record-suggestion.rs:10:20
    |
-LL |     let q = A { c: 5 .. Default::default() };
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found struct `std::ops::Range`
+LL |     let q = A { c: 5..Default::default() };
+   |                    ^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found struct `std::ops::Range`
    |
    = note: expected type `u64`
             found struct `std::ops::Range<{integer}>`
@@ -10,15 +10,28 @@ LL |     let q = A { c: 5 .. Default::default() };
 error[E0063]: missing fields `b` and `d` in initializer of `A`
   --> $DIR/struct-record-suggestion.rs:10:13
    |
-LL |     let q = A { c: 5 .. Default::default() };
+LL |     let q = A { c: 5..Default::default() };
    |             ^ missing `b` and `d`
    |
 help: to set the remaining fields from `Default::default()`, separate the last named field with a comma
    |
-LL |     let q = A { c: 5, .. Default::default() };
+LL |     let q = A { c: 5,..Default::default() };
    |                     +
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/struct-record-suggestion.rs:24:20
+   |
+LL |     let q = B { b: 1..Default::default() };
+   |                    ^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found struct `std::ops::Range`
+   |
+   = note: expected type `u32`
+            found struct `std::ops::Range<{integer}>`
+help: to set the remaining fields from `Default::default()`, separate the last named field with a comma
+   |
+LL |     let q = B { b: 1,..Default::default() };
+   |                     +
+
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0063, E0308.
 For more information about an error, try `rustc --explain E0063`.