about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2024-11-26 22:28:51 +0000
committerEsteban Küber <esteban@kuber.com.ar>2024-12-09 21:55:12 +0000
commite0752ad2572218dfc7764951b72d4e3e84ea842c (patch)
tree4bc9be6efd087863af533a30f2f7db9743964295 /compiler
parent550bcae8aa7859abace52c20b8b9149ae6cb37f1 (diff)
downloadrust-e0752ad2572218dfc7764951b72d4e3e84ea842c.tar.gz
rust-e0752ad2572218dfc7764951b72d4e3e84ea842c.zip
Provide diagnostic for `Struct(a, .., z)` expression
People might extrapolate from `Struct { .. }` that `Struct(..)` would work, but it doesn't.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs31
1 files changed, 31 insertions, 0 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,