mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
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:
parent
550bcae8aa
commit
e0752ad257
@ -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,
|
||||
|
@ -38,6 +38,7 @@ fn main() {
|
||||
|
||||
take_range(..);
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
//~| HELP you might have meant
|
||||
//~| HELP consider borrowing here
|
||||
//~| SUGGESTION &(
|
||||
|
||||
|
@ -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}>`
|
||||
|
@ -23,6 +23,7 @@ fn main() {
|
||||
|
||||
take_range(&(..));
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
//~| HELP you might have meant
|
||||
//~| HELP consider borrowing here
|
||||
//~| SUGGESTION &(
|
||||
|
||||
|
@ -23,6 +23,7 @@ fn main() {
|
||||
|
||||
take_range(..);
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
//~| HELP you might have meant
|
||||
//~| HELP consider borrowing here
|
||||
//~| SUGGESTION &(
|
||||
|
||||
|
@ -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}>`
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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`.
|
||||
|
Loading…
Reference in New Issue
Block a user