about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs31
-rw-r--r--tests/ui/range/issue-54505-no-std.rs1
-rw-r--r--tests/ui/range/issue-54505-no-std.stderr11
-rw-r--r--tests/ui/range/issue-54505.fixed1
-rw-r--r--tests/ui/range/issue-54505.rs1
-rw-r--r--tests/ui/range/issue-54505.stderr11
-rw-r--r--tests/ui/structs/default-field-values-failures.rs7
-rw-r--r--tests/ui/structs/default-field-values-failures.stderr68
8 files changed, 123 insertions, 8 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 44582390a4b..6b1cceefbee 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -903,6 +903,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
 
+        let detect_dotdot = |err: &mut Diag<'_>, ty: Ty<'_>, expr: &hir::Expr<'_>| {
+            if let ty::Adt(adt, _) = ty.kind()
+                && self.tcx().lang_items().get(hir::LangItem::RangeFull) == Some(adt.did())
+                && let hir::ExprKind::Struct(
+                    hir::QPath::LangItem(hir::LangItem::RangeFull, _),
+                    [],
+                    _,
+                ) = expr.kind
+            {
+                // We have `Foo(a, .., c)`, where the user might be trying to use the "rest" syntax
+                // from default field values, which is not supported on tuples.
+                let explanation = if self.tcx.features().default_field_values() {
+                    "this is only supported on non-tuple struct literals"
+                } else if self.tcx.sess.is_nightly_build() {
+                    "this is only supported on non-tuple struct literals when \
+                     `#![feature(default_field_values)]` is enabled"
+                } else {
+                    "this is not supported"
+                };
+                let msg = format!(
+                    "you might have meant to use `..` to skip providing a value for \
+                     expected fields, but {explanation}; it is instead interpreted as a \
+                     `std::ops::RangeFull` literal",
+                );
+                err.span_help(expr.span, msg);
+            }
+        };
+
         let mut reported = None;
         errors.retain(|error| {
             let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) =
@@ -1009,6 +1037,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 tuple_arguments,
             );
             suggest_confusable(&mut err);
+            detect_dotdot(&mut err, provided_ty, provided_args[provided_idx]);
             return err.emit();
         }
 
@@ -1133,6 +1162,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         None,
                         None,
                     );
+                    detect_dotdot(&mut err, provided_ty, provided_args[provided_idx]);
                 }
                 Error::Extra(arg_idx) => {
                     let (provided_ty, provided_span) = provided_arg_tys[arg_idx];
@@ -1216,6 +1246,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         };
                         prev_extra_idx = Some(arg_idx.index())
                     }
+                    detect_dotdot(&mut err, provided_ty, provided_args[arg_idx]);
                 }
                 Error::Missing(expected_idx) => {
                     // If there are multiple missing arguments adjacent to each other,
diff --git a/tests/ui/range/issue-54505-no-std.rs b/tests/ui/range/issue-54505-no-std.rs
index a1595685372..0c913f766b7 100644
--- a/tests/ui/range/issue-54505-no-std.rs
+++ b/tests/ui/range/issue-54505-no-std.rs
@@ -38,6 +38,7 @@ fn main() {
 
     take_range(..);
     //~^ ERROR mismatched types [E0308]
+    //~| HELP you might have meant
     //~| HELP consider borrowing here
     //~| SUGGESTION &(
 
diff --git a/tests/ui/range/issue-54505-no-std.stderr b/tests/ui/range/issue-54505-no-std.stderr
index f15a0ae6138..2aa1d584046 100644
--- a/tests/ui/range/issue-54505-no-std.stderr
+++ b/tests/ui/range/issue-54505-no-std.stderr
@@ -53,13 +53,18 @@ note: function defined here
    |
 LL | fn take_range(_r: &impl RangeBounds<i8>) {}
    |    ^^^^^^^^^^ -------------------------
+help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals when `#![feature(default_field_values)]` is enabled; it is instead interpreted as a `std::ops::RangeFull` literal
+  --> $DIR/issue-54505-no-std.rs:39:16
+   |
+LL |     take_range(..);
+   |                ^^
 help: consider borrowing here
    |
 LL |     take_range(&(..));
    |                ++  +
 
 error[E0308]: mismatched types
-  --> $DIR/issue-54505-no-std.rs:44:16
+  --> $DIR/issue-54505-no-std.rs:45:16
    |
 LL |     take_range(0..=1);
    |     ---------- ^^^^^ expected `&_`, found `RangeInclusive<{integer}>`
@@ -79,7 +84,7 @@ LL |     take_range(&(0..=1));
    |                ++     +
 
 error[E0308]: mismatched types
-  --> $DIR/issue-54505-no-std.rs:49:16
+  --> $DIR/issue-54505-no-std.rs:50:16
    |
 LL |     take_range(..5);
    |     ---------- ^^^ expected `&_`, found `RangeTo<{integer}>`
@@ -99,7 +104,7 @@ LL |     take_range(&(..5));
    |                ++   +
 
 error[E0308]: mismatched types
-  --> $DIR/issue-54505-no-std.rs:54:16
+  --> $DIR/issue-54505-no-std.rs:55:16
    |
 LL |     take_range(..=42);
    |     ---------- ^^^^^ expected `&_`, found `RangeToInclusive<{integer}>`
diff --git a/tests/ui/range/issue-54505.fixed b/tests/ui/range/issue-54505.fixed
index 054d3c2cf5e..08a2682140a 100644
--- a/tests/ui/range/issue-54505.fixed
+++ b/tests/ui/range/issue-54505.fixed
@@ -23,6 +23,7 @@ fn main() {
 
     take_range(&(..));
     //~^ ERROR mismatched types [E0308]
+    //~| HELP you might have meant
     //~| HELP consider borrowing here
     //~| SUGGESTION &(
 
diff --git a/tests/ui/range/issue-54505.rs b/tests/ui/range/issue-54505.rs
index f5cec831760..0a9d7083e4f 100644
--- a/tests/ui/range/issue-54505.rs
+++ b/tests/ui/range/issue-54505.rs
@@ -23,6 +23,7 @@ fn main() {
 
     take_range(..);
     //~^ ERROR mismatched types [E0308]
+    //~| HELP you might have meant
     //~| HELP consider borrowing here
     //~| SUGGESTION &(
 
diff --git a/tests/ui/range/issue-54505.stderr b/tests/ui/range/issue-54505.stderr
index 0e959fc05e2..291e097e865 100644
--- a/tests/ui/range/issue-54505.stderr
+++ b/tests/ui/range/issue-54505.stderr
@@ -53,13 +53,18 @@ note: function defined here
    |
 LL | fn take_range(_r: &impl RangeBounds<i8>) {}
    |    ^^^^^^^^^^ -------------------------
+help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals when `#![feature(default_field_values)]` is enabled; it is instead interpreted as a `std::ops::RangeFull` literal
+  --> $DIR/issue-54505.rs:24:16
+   |
+LL |     take_range(..);
+   |                ^^
 help: consider borrowing here
    |
 LL |     take_range(&(..));
    |                ++  +
 
 error[E0308]: mismatched types
-  --> $DIR/issue-54505.rs:29:16
+  --> $DIR/issue-54505.rs:30:16
    |
 LL |     take_range(0..=1);
    |     ---------- ^^^^^ expected `&_`, found `RangeInclusive<{integer}>`
@@ -79,7 +84,7 @@ LL |     take_range(&(0..=1));
    |                ++     +
 
 error[E0308]: mismatched types
-  --> $DIR/issue-54505.rs:34:16
+  --> $DIR/issue-54505.rs:35:16
    |
 LL |     take_range(..5);
    |     ---------- ^^^ expected `&_`, found `RangeTo<{integer}>`
@@ -99,7 +104,7 @@ LL |     take_range(&(..5));
    |                ++   +
 
 error[E0308]: mismatched types
-  --> $DIR/issue-54505.rs:39:16
+  --> $DIR/issue-54505.rs:40:16
    |
 LL |     take_range(..=42);
    |     ---------- ^^^^^ expected `&_`, found `RangeToInclusive<{integer}>`
diff --git a/tests/ui/structs/default-field-values-failures.rs b/tests/ui/structs/default-field-values-failures.rs
index 27eff70dd3e..e850ad387aa 100644
--- a/tests/ui/structs/default-field-values-failures.rs
+++ b/tests/ui/structs/default-field-values-failures.rs
@@ -48,4 +48,11 @@ fn main () {
     let _ = Bar::default(); // silenced
     let _ = Bar { bar: S, .. }; // ok
     let _ = Qux::<4> { .. };
+    let _ = Rak(..); //~ ERROR E0308
+    //~^ you might have meant to use `..` to skip providing
+    let _ = Rak(0, ..); //~ ERROR E0061
+    //~^ you might have meant to use `..` to skip providing
+    let _ = Rak(.., 0); //~ ERROR E0061
+    //~^ you might have meant to use `..` to skip providing
+    let _ = Rak { .. }; // ok
 }
diff --git a/tests/ui/structs/default-field-values-failures.stderr b/tests/ui/structs/default-field-values-failures.stderr
index 3564c1dc20e..bd8d1922e91 100644
--- a/tests/ui/structs/default-field-values-failures.stderr
+++ b/tests/ui/structs/default-field-values-failures.stderr
@@ -35,12 +35,76 @@ error: missing mandatory field `bar`
 LL |     let _ = Bar { .. };
    |                     ^
 
+error[E0308]: mismatched types
+  --> $DIR/default-field-values-failures.rs:51:17
+   |
+LL |     let _ = Rak(..);
+   |             --- ^^ expected `i32`, found `RangeFull`
+   |             |
+   |             arguments to this struct are incorrect
+   |
+note: tuple struct defined here
+  --> $DIR/default-field-values-failures.rs:26:12
+   |
+LL | pub struct Rak(i32 = 42);
+   |            ^^^
+help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
+  --> $DIR/default-field-values-failures.rs:51:17
+   |
+LL |     let _ = Rak(..);
+   |                 ^^
+
+error[E0061]: this struct takes 1 argument but 2 arguments were supplied
+  --> $DIR/default-field-values-failures.rs:53:13
+   |
+LL |     let _ = Rak(0, ..);
+   |             ^^^    -- unexpected argument #2 of type `RangeFull`
+   |
+help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
+  --> $DIR/default-field-values-failures.rs:53:20
+   |
+LL |     let _ = Rak(0, ..);
+   |                    ^^
+note: tuple struct defined here
+  --> $DIR/default-field-values-failures.rs:26:12
+   |
+LL | pub struct Rak(i32 = 42);
+   |            ^^^
+help: remove the extra argument
+   |
+LL -     let _ = Rak(0, ..);
+LL +     let _ = Rak(0);
+   |
+
+error[E0061]: this struct takes 1 argument but 2 arguments were supplied
+  --> $DIR/default-field-values-failures.rs:55:13
+   |
+LL |     let _ = Rak(.., 0);
+   |             ^^^ -- unexpected argument #1 of type `RangeFull`
+   |
+help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
+  --> $DIR/default-field-values-failures.rs:55:17
+   |
+LL |     let _ = Rak(.., 0);
+   |                 ^^
+note: tuple struct defined here
+  --> $DIR/default-field-values-failures.rs:26:12
+   |
+LL | pub struct Rak(i32 = 42);
+   |            ^^^
+help: remove the extra argument
+   |
+LL -     let _ = Rak(.., 0);
+LL +     let _ = Rak(0);
+   |
+
 error: generic `Self` types are currently not permitted in anonymous constants
   --> $DIR/default-field-values-failures.rs:20:14
    |
 LL |     bar: S = Self::S,
    |              ^^^^
 
-error: aborting due to 5 previous errors
+error: aborting due to 8 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0061, E0277, E0308.
+For more information about an error, try `rustc --explain E0061`.