diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2024-11-26 22:28:51 +0000 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2024-12-09 21:55:12 +0000 |
| commit | e0752ad2572218dfc7764951b72d4e3e84ea842c (patch) | |
| tree | 4bc9be6efd087863af533a30f2f7db9743964295 /compiler | |
| parent | 550bcae8aa7859abace52c20b8b9149ae6cb37f1 (diff) | |
| download | rust-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.rs | 31 |
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, |
