Skip to content

Commit 922e6bb

Browse files
committed
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: (), .. }; | ++++ ```
1 parent 6a64e3b commit 922e6bb

File tree

5 files changed

+197
-0
lines changed

5 files changed

+197
-0
lines changed

compiler/rustc_hir_typeck/src/expr.rs

+30
Original file line numberDiff line numberDiff line change
@@ -2349,6 +2349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23492349
self.report_missing_fields(
23502350
adt_ty,
23512351
path_span,
2352+
expr.span,
23522353
remaining_fields,
23532354
variant,
23542355
hir_fields,
@@ -2386,6 +2387,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23862387
&self,
23872388
adt_ty: Ty<'tcx>,
23882389
span: Span,
2390+
full_span: Span,
23892391
remaining_fields: UnordMap<Ident, (FieldIdx, &ty::FieldDef)>,
23902392
variant: &'tcx ty::VariantDef,
23912393
hir_fields: &'tcx [hir::ExprField<'tcx>],
@@ -2425,6 +2427,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24252427
);
24262428
err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}"));
24272429

2430+
if remaining_fields.items().all(|(_, (_, field))| field.value.is_some())
2431+
&& self.tcx.sess.is_nightly_build()
2432+
{
2433+
let msg = format!(
2434+
"all remaining fields have default values, {you_can} use those values with `..`",
2435+
you_can = if self.tcx.features().default_field_values() {
2436+
"you can"
2437+
} else {
2438+
"if you added `#![feature(default_field_values)]` to your crate you could"
2439+
},
2440+
);
2441+
if let Some(hir_field) = hir_fields.last() {
2442+
err.span_suggestion_verbose(
2443+
hir_field.span.shrink_to_hi(),
2444+
msg,
2445+
", ..".to_string(),
2446+
Applicability::MachineApplicable,
2447+
);
2448+
} else if hir_fields.is_empty() {
2449+
err.span_suggestion_verbose(
2450+
span.shrink_to_hi().with_hi(full_span.hi()),
2451+
msg,
2452+
" { .. }".to_string(),
2453+
Applicability::MachineApplicable,
2454+
);
2455+
}
2456+
}
2457+
24282458
if let Some(hir_field) = hir_fields.last() {
24292459
self.suggest_fru_from_range_and_emit(hir_field, variant, args, err);
24302460
} else {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
error[E0658]: default values on fields are experimental
2+
--> $DIR/non-exhaustive-ctor.rs:9:22
3+
|
4+
LL | pub field: () = (),
5+
| ^^^^^
6+
|
7+
= note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information
8+
= help: add `#![feature(default_field_values)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error[E0658]: default values on fields are experimental
12+
--> $DIR/non-exhaustive-ctor.rs:11:25
13+
|
14+
LL | pub field1: Priv = Priv,
15+
| ^^^^^^^
16+
|
17+
= note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information
18+
= help: add `#![feature(default_field_values)]` to the crate attributes to enable
19+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
20+
21+
error[E0658]: default values on fields are experimental
22+
--> $DIR/non-exhaustive-ctor.rs:13:25
23+
|
24+
LL | pub field2: Priv = Priv,
25+
| ^^^^^^^
26+
|
27+
= note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information
28+
= help: add `#![feature(default_field_values)]` to the crate attributes to enable
29+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
30+
31+
error[E0797]: base expression required after `..`
32+
--> $DIR/non-exhaustive-ctor.rs:20:19
33+
|
34+
LL | let _ = S { .. }; // ok
35+
| ^
36+
|
37+
help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
38+
|
39+
LL + #![feature(default_field_values)]
40+
|
41+
help: add a base expression here
42+
|
43+
LL | let _ = S { ../* expr */ }; // ok
44+
| ++++++++++
45+
46+
error[E0797]: base expression required after `..`
47+
--> $DIR/non-exhaustive-ctor.rs:22:30
48+
|
49+
LL | let _ = S { field: (), .. }; // ok
50+
| ^
51+
|
52+
help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
53+
|
54+
LL + #![feature(default_field_values)]
55+
|
56+
help: add a base expression here
57+
|
58+
LL | let _ = S { field: (), ../* expr */ }; // ok
59+
| ++++++++++
60+
61+
error[E0063]: missing fields `field`, `field1` and `field2` in initializer of `S`
62+
--> $DIR/non-exhaustive-ctor.rs:24:13
63+
|
64+
LL | let _ = S { };
65+
| ^ missing `field`, `field1` and `field2`
66+
|
67+
help: all remaining fields have default values, if you added `#![feature(default_field_values)]` to your crate you could use those values with `..`
68+
|
69+
LL | let _ = S { .. };
70+
| ~~~~~~
71+
72+
error[E0063]: missing fields `field1` and `field2` in initializer of `S`
73+
--> $DIR/non-exhaustive-ctor.rs:26:13
74+
|
75+
LL | let _ = S { field: () };
76+
| ^ missing `field1` and `field2`
77+
|
78+
help: all remaining fields have default values, if you added `#![feature(default_field_values)]` to your crate you could use those values with `..`
79+
|
80+
LL | let _ = S { field: (), .. };
81+
| ++++
82+
83+
error: aborting due to 7 previous errors
84+
85+
Some errors have detailed explanations: E0063, E0658, E0797.
86+
For more information about an error, try `rustc --explain E0063`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//@ revisions: enabled disabled
2+
//@[enabled] run-rustfix
3+
#![allow(private_interfaces, dead_code)]
4+
#![cfg_attr(enabled, feature(default_field_values))]
5+
use m::S;
6+
7+
mod m {
8+
pub struct S {
9+
pub field: () = (),
10+
//[disabled]~^ ERROR default values on fields are experimental
11+
pub field1: Priv = Priv,
12+
//[disabled]~^ ERROR default values on fields are experimental
13+
pub field2: Priv = Priv,
14+
//[disabled]~^ ERROR default values on fields are experimental
15+
}
16+
struct Priv;
17+
}
18+
19+
fn main() {
20+
let _ = S { .. }; // ok
21+
//[disabled]~^ ERROR base expression required after `..`
22+
let _ = S { field: (), .. }; // ok
23+
//[disabled]~^ ERROR base expression required after `..`
24+
let _ = S { .. };
25+
//~^ ERROR missing fields `field`, `field1` and `field2`
26+
let _ = S { field: (), .. };
27+
//~^ ERROR missing fields `field1` and `field2`
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0063]: missing fields `field`, `field1` and `field2` in initializer of `S`
2+
--> $DIR/non-exhaustive-ctor.rs:24:13
3+
|
4+
LL | let _ = S { };
5+
| ^ missing `field`, `field1` and `field2`
6+
|
7+
help: all remaining fields have default values, you can use those values with `..`
8+
|
9+
LL | let _ = S { .. };
10+
| ~~~~~~
11+
12+
error[E0063]: missing fields `field1` and `field2` in initializer of `S`
13+
--> $DIR/non-exhaustive-ctor.rs:26:13
14+
|
15+
LL | let _ = S { field: () };
16+
| ^ missing `field1` and `field2`
17+
|
18+
help: all remaining fields have default values, you can use those values with `..`
19+
|
20+
LL | let _ = S { field: (), .. };
21+
| ++++
22+
23+
error: aborting due to 2 previous errors
24+
25+
For more information about this error, try `rustc --explain E0063`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//@ revisions: enabled disabled
2+
//@[enabled] run-rustfix
3+
#![allow(private_interfaces, dead_code)]
4+
#![cfg_attr(enabled, feature(default_field_values))]
5+
use m::S;
6+
7+
mod m {
8+
pub struct S {
9+
pub field: () = (),
10+
//[disabled]~^ ERROR default values on fields are experimental
11+
pub field1: Priv = Priv,
12+
//[disabled]~^ ERROR default values on fields are experimental
13+
pub field2: Priv = Priv,
14+
//[disabled]~^ ERROR default values on fields are experimental
15+
}
16+
struct Priv;
17+
}
18+
19+
fn main() {
20+
let _ = S { .. }; // ok
21+
//[disabled]~^ ERROR base expression required after `..`
22+
let _ = S { field: (), .. }; // ok
23+
//[disabled]~^ ERROR base expression required after `..`
24+
let _ = S { };
25+
//~^ ERROR missing fields `field`, `field1` and `field2`
26+
let _ = S { field: () };
27+
//~^ ERROR missing fields `field1` and `field2`
28+
}

0 commit comments

Comments
 (0)