Skip to content

Commit 4adec34

Browse files
committed
Handle missing fields diagnostics
1 parent fcb2013 commit 4adec34

File tree

11 files changed

+59
-12
lines changed

11 files changed

+59
-12
lines changed

crates/hir-def/src/body/lower.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -546,9 +546,10 @@ impl ExprCollector<'_> {
546546
})
547547
.collect();
548548
let spread = nfl.spread().map(|s| self.collect_expr(s));
549-
Expr::RecordLit { path, fields, spread }
549+
let ellipsis = nfl.dotdot_token().is_some();
550+
Expr::RecordLit { path, fields, spread, ellipsis }
550551
} else {
551-
Expr::RecordLit { path, fields: Box::default(), spread: None }
552+
Expr::RecordLit { path, fields: Box::default(), spread: None, ellipsis: false }
552553
};
553554

554555
self.alloc_expr(record_lit, syntax_ptr)

crates/hir-def/src/body/pretty.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ impl Printer<'_> {
398398
self.print_expr(*expr);
399399
}
400400
}
401-
Expr::RecordLit { path, fields, spread } => {
401+
Expr::RecordLit { path, fields, spread, ellipsis: _ } => {
402402
match path {
403403
Some(path) => self.print_path(path),
404404
None => w!(self, "�"),

crates/hir-def/src/data/adt.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ pub struct FieldData {
8585
pub name: Name,
8686
pub type_ref: TypeRefId,
8787
pub visibility: RawVisibility,
88+
pub has_default: bool,
8889
}
8990

9091
fn repr_from_value(
@@ -478,5 +479,6 @@ fn lower_field(
478479
name: field.name.clone(),
479480
type_ref: field.type_ref,
480481
visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
482+
has_default: field.has_default,
481483
}
482484
}

crates/hir-def/src/hir.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ pub enum Expr {
255255
path: Option<Box<Path>>,
256256
fields: Box<[RecordLitField]>,
257257
spread: Option<ExprId>,
258+
ellipsis: bool,
258259
},
259260
Field {
260261
expr: ExprId,

crates/hir-def/src/item_tree.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,7 @@ pub struct Field {
10011001
pub name: Name,
10021002
pub type_ref: TypeRefId,
10031003
pub visibility: RawVisibilityId,
1004+
pub has_default: bool,
10041005
}
10051006

10061007
#[derive(Debug, Clone, Eq, PartialEq)]

crates/hir-def/src/item_tree/lower.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,9 @@ impl<'a> Ctx<'a> {
319319
};
320320
let visibility = self.lower_visibility(field);
321321
let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
322+
let has_default = field.expr().is_some();
322323

323-
Field { name, type_ref, visibility }
324+
Field { name, type_ref, visibility, has_default }
324325
}
325326

326327
fn lower_tuple_field(
@@ -332,7 +333,7 @@ impl<'a> Ctx<'a> {
332333
let name = Name::new_tuple_field(idx);
333334
let visibility = self.lower_visibility(field);
334335
let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
335-
Field { name, type_ref, visibility }
336+
Field { name, type_ref, visibility, has_default: false }
336337
}
337338

338339
fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {

crates/hir-def/src/item_tree/pretty.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,9 @@ impl Printer<'_> {
135135
self.whitespace();
136136
w!(self, "{{");
137137
self.indented(|this| {
138-
for (idx, Field { name, type_ref, visibility }) in fields.iter().enumerate() {
138+
for (idx, Field { name, type_ref, visibility, has_default: _ }) in
139+
fields.iter().enumerate()
140+
{
139141
this.print_attrs_of(
140142
AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))),
141143
"\n",
@@ -151,7 +153,9 @@ impl Printer<'_> {
151153
FieldsShape::Tuple => {
152154
w!(self, "(");
153155
self.indented(|this| {
154-
for (idx, Field { name, type_ref, visibility }) in fields.iter().enumerate() {
156+
for (idx, Field { name, type_ref, visibility, has_default: _ }) in
157+
fields.iter().enumerate()
158+
{
155159
this.print_attrs_of(
156160
AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))),
157161
"\n",

crates/hir-ty/src/diagnostics/expr.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -547,8 +547,8 @@ pub fn record_literal_missing_fields(
547547
id: ExprId,
548548
expr: &Expr,
549549
) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> {
550-
let (fields, exhaustive) = match expr {
551-
Expr::RecordLit { fields, spread, .. } => (fields, spread.is_none()),
550+
let (fields, exhaustive, ellipsis) = match expr {
551+
Expr::RecordLit { fields, spread, ellipsis, .. } => (fields, spread.is_none(), *ellipsis),
552552
_ => return None,
553553
};
554554

@@ -563,7 +563,13 @@ pub fn record_literal_missing_fields(
563563
let missed_fields: Vec<LocalFieldId> = variant_data
564564
.fields()
565565
.iter()
566-
.filter_map(|(f, d)| if specified_fields.contains(&d.name) { None } else { Some(f) })
566+
.filter_map(|(f, d)| {
567+
if (ellipsis && d.has_default) || specified_fields.contains(&d.name) {
568+
None
569+
} else {
570+
Some(f)
571+
}
572+
})
567573
.collect();
568574
if missed_fields.is_empty() {
569575
return None;

crates/hir-ty/src/infer/mutability.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ impl InferenceContext<'_> {
121121
Expr::Become { expr } => {
122122
self.infer_mut_expr(*expr, Mutability::Not);
123123
}
124-
Expr::RecordLit { path: _, fields, spread } => {
124+
Expr::RecordLit { path: _, fields, spread, ellipsis: _ } => {
125125
self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr).chain(*spread))
126126
}
127127
&Expr::Index { base, index } => {

crates/hir-ty/src/mir/lower.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -823,7 +823,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
823823
}
824824
Expr::Become { .. } => not_supported!("tail-calls"),
825825
Expr::Yield { .. } => not_supported!("yield"),
826-
Expr::RecordLit { fields, path, spread } => {
826+
Expr::RecordLit { fields, path, spread, ellipsis: _ } => {
827827
let spread_place = match spread {
828828
&Some(it) => {
829829
let Some((p, c)) = self.lower_expr_as_place(current, it, true)? else {

crates/ide-diagnostics/src/handlers/missing_fields.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,4 +845,35 @@ pub struct Claims {
845845
"#,
846846
);
847847
}
848+
849+
#[test]
850+
fn default_field_values() {
851+
check_diagnostics(
852+
r#"
853+
struct F {
854+
field1: i32 = 4,
855+
field2: bool,
856+
}
857+
858+
fn f() {
859+
let _f = F {
860+
field2: true,
861+
..
862+
};
863+
864+
let _f = F {
865+
//^ 💡 error: missing structure fields:
866+
//| - field1
867+
field2: true,
868+
};
869+
870+
let _f = F {
871+
//^ 💡 error: missing structure fields:
872+
//| - field2
873+
..
874+
};
875+
}
876+
"#,
877+
);
878+
}
848879
}

0 commit comments

Comments
 (0)