1
Fork 0

Provide diagnostic for Struct(a, .., z) expression

People might extrapolate from `Struct { .. }` that `Struct(..)` would work, but it doesn't.
This commit is contained in:
Esteban Küber 2024-11-26 22:28:51 +00:00
parent 550bcae8aa
commit e0752ad257
8 changed files with 123 additions and 8 deletions

View file

@ -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,