Detect missing fields with default values and suggest ..
When a struct definition has default field values, and the use struct ctor has missing field, if all those missing fields have defaults suggest `..`:
```
error[E0063]: missing fields `field1` and `field2` in initializer of `S`
--> $DIR/non-exhaustive-ctor.rs:16:13
|
LL | let _ = S { field: () };
| ^ missing `field1` and `field2`
|
help: all remaining fields have defaults, use `..`
|
LL | let _ = S { field: (), .. };
| ++++
```
This commit is contained in:
parent
6a64e3b897
commit
922e6bb2d4
5 changed files with 197 additions and 0 deletions
|
|
@ -2349,6 +2349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.report_missing_fields(
|
||||
adt_ty,
|
||||
path_span,
|
||||
expr.span,
|
||||
remaining_fields,
|
||||
variant,
|
||||
hir_fields,
|
||||
|
|
@ -2386,6 +2387,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&self,
|
||||
adt_ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
full_span: Span,
|
||||
remaining_fields: UnordMap<Ident, (FieldIdx, &ty::FieldDef)>,
|
||||
variant: &'tcx ty::VariantDef,
|
||||
hir_fields: &'tcx [hir::ExprField<'tcx>],
|
||||
|
|
@ -2425,6 +2427,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
);
|
||||
err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}"));
|
||||
|
||||
if remaining_fields.items().all(|(_, (_, field))| field.value.is_some())
|
||||
&& self.tcx.sess.is_nightly_build()
|
||||
{
|
||||
let msg = format!(
|
||||
"all remaining fields have default values, {you_can} use those values with `..`",
|
||||
you_can = if self.tcx.features().default_field_values() {
|
||||
"you can"
|
||||
} else {
|
||||
"if you added `#![feature(default_field_values)]` to your crate you could"
|
||||
},
|
||||
);
|
||||
if let Some(hir_field) = hir_fields.last() {
|
||||
err.span_suggestion_verbose(
|
||||
hir_field.span.shrink_to_hi(),
|
||||
msg,
|
||||
", ..".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if hir_fields.is_empty() {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi().with_hi(full_span.hi()),
|
||||
msg,
|
||||
" { .. }".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(hir_field) = hir_fields.last() {
|
||||
self.suggest_fru_from_range_and_emit(hir_field, variant, args, err);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
error[E0658]: default values on fields are experimental
|
||||
--> $DIR/non-exhaustive-ctor.rs:9:22
|
||||
|
|
||||
LL | pub field: () = (),
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information
|
||||
= help: add `#![feature(default_field_values)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: default values on fields are experimental
|
||||
--> $DIR/non-exhaustive-ctor.rs:11:25
|
||||
|
|
||||
LL | pub field1: Priv = Priv,
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information
|
||||
= help: add `#![feature(default_field_values)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: default values on fields are experimental
|
||||
--> $DIR/non-exhaustive-ctor.rs:13:25
|
||||
|
|
||||
LL | pub field2: Priv = Priv,
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information
|
||||
= help: add `#![feature(default_field_values)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/non-exhaustive-ctor.rs:20:19
|
||||
|
|
||||
LL | let _ = S { .. }; // ok
|
||||
| ^
|
||||
|
|
||||
help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
|
||||
|
|
||||
LL + #![feature(default_field_values)]
|
||||
|
|
||||
help: add a base expression here
|
||||
|
|
||||
LL | let _ = S { ../* expr */ }; // ok
|
||||
| ++++++++++
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/non-exhaustive-ctor.rs:22:30
|
||||
|
|
||||
LL | let _ = S { field: (), .. }; // ok
|
||||
| ^
|
||||
|
|
||||
help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
|
||||
|
|
||||
LL + #![feature(default_field_values)]
|
||||
|
|
||||
help: add a base expression here
|
||||
|
|
||||
LL | let _ = S { field: (), ../* expr */ }; // ok
|
||||
| ++++++++++
|
||||
|
||||
error[E0063]: missing fields `field`, `field1` and `field2` in initializer of `S`
|
||||
--> $DIR/non-exhaustive-ctor.rs:24:13
|
||||
|
|
||||
LL | let _ = S { };
|
||||
| ^ missing `field`, `field1` and `field2`
|
||||
|
|
||||
help: all remaining fields have default values, if you added `#![feature(default_field_values)]` to your crate you could use those values with `..`
|
||||
|
|
||||
LL | let _ = S { .. };
|
||||
| ~~~~~~
|
||||
|
||||
error[E0063]: missing fields `field1` and `field2` in initializer of `S`
|
||||
--> $DIR/non-exhaustive-ctor.rs:26:13
|
||||
|
|
||||
LL | let _ = S { field: () };
|
||||
| ^ missing `field1` and `field2`
|
||||
|
|
||||
help: all remaining fields have default values, if you added `#![feature(default_field_values)]` to your crate you could use those values with `..`
|
||||
|
|
||||
LL | let _ = S { field: (), .. };
|
||||
| ++++
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0063, E0658, E0797.
|
||||
For more information about an error, try `rustc --explain E0063`.
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
//@ revisions: enabled disabled
|
||||
//@[enabled] run-rustfix
|
||||
#![allow(private_interfaces, dead_code)]
|
||||
#![cfg_attr(enabled, feature(default_field_values))]
|
||||
use m::S;
|
||||
|
||||
mod m {
|
||||
pub struct S {
|
||||
pub field: () = (),
|
||||
//[disabled]~^ ERROR default values on fields are experimental
|
||||
pub field1: Priv = Priv,
|
||||
//[disabled]~^ ERROR default values on fields are experimental
|
||||
pub field2: Priv = Priv,
|
||||
//[disabled]~^ ERROR default values on fields are experimental
|
||||
}
|
||||
struct Priv;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = S { .. }; // ok
|
||||
//[disabled]~^ ERROR base expression required after `..`
|
||||
let _ = S { field: (), .. }; // ok
|
||||
//[disabled]~^ ERROR base expression required after `..`
|
||||
let _ = S { .. };
|
||||
//~^ ERROR missing fields `field`, `field1` and `field2`
|
||||
let _ = S { field: (), .. };
|
||||
//~^ ERROR missing fields `field1` and `field2`
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
error[E0063]: missing fields `field`, `field1` and `field2` in initializer of `S`
|
||||
--> $DIR/non-exhaustive-ctor.rs:24:13
|
||||
|
|
||||
LL | let _ = S { };
|
||||
| ^ missing `field`, `field1` and `field2`
|
||||
|
|
||||
help: all remaining fields have default values, you can use those values with `..`
|
||||
|
|
||||
LL | let _ = S { .. };
|
||||
| ~~~~~~
|
||||
|
||||
error[E0063]: missing fields `field1` and `field2` in initializer of `S`
|
||||
--> $DIR/non-exhaustive-ctor.rs:26:13
|
||||
|
|
||||
LL | let _ = S { field: () };
|
||||
| ^ missing `field1` and `field2`
|
||||
|
|
||||
help: all remaining fields have default values, you can use those values with `..`
|
||||
|
|
||||
LL | let _ = S { field: (), .. };
|
||||
| ++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0063`.
|
||||
28
tests/ui/structs/default-field-values/non-exhaustive-ctor.rs
Normal file
28
tests/ui/structs/default-field-values/non-exhaustive-ctor.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
//@ revisions: enabled disabled
|
||||
//@[enabled] run-rustfix
|
||||
#![allow(private_interfaces, dead_code)]
|
||||
#![cfg_attr(enabled, feature(default_field_values))]
|
||||
use m::S;
|
||||
|
||||
mod m {
|
||||
pub struct S {
|
||||
pub field: () = (),
|
||||
//[disabled]~^ ERROR default values on fields are experimental
|
||||
pub field1: Priv = Priv,
|
||||
//[disabled]~^ ERROR default values on fields are experimental
|
||||
pub field2: Priv = Priv,
|
||||
//[disabled]~^ ERROR default values on fields are experimental
|
||||
}
|
||||
struct Priv;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = S { .. }; // ok
|
||||
//[disabled]~^ ERROR base expression required after `..`
|
||||
let _ = S { field: (), .. }; // ok
|
||||
//[disabled]~^ ERROR base expression required after `..`
|
||||
let _ = S { };
|
||||
//~^ ERROR missing fields `field`, `field1` and `field2`
|
||||
let _ = S { field: () };
|
||||
//~^ ERROR missing fields `field1` and `field2`
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue