about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorShoyu Vanilla <modulo641@gmail.com>2025-01-24 02:54:54 +0900
committerShoyu Vanilla <modulo641@gmail.com>2025-01-27 19:38:39 +0900
commit5ca9f522dd985ac63df6301bb9be391b68929a77 (patch)
tree24f424dbbd06ad3d0444cd66af126f6733fe601a /src
parentd18afd394ce3342d04f020986bab0d82f51fdbdc (diff)
downloadrust-5ca9f522dd985ac63df6301bb9be391b68929a77.tar.gz
rust-5ca9f522dd985ac63df6301bb9be391b68929a77.zip
Handle missing fields diagnostics
Diffstat (limited to 'src')
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs31
11 files changed, 59 insertions, 12 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
index 8fc19854033..aaa260a358b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
@@ -85,6 +85,7 @@ pub struct FieldData {
     pub name: Name,
     pub type_ref: TypeRefId,
     pub visibility: RawVisibility,
+    pub has_default: bool,
 }
 
 fn repr_from_value(
@@ -478,5 +479,6 @@ fn lower_field(
         name: field.name.clone(),
         type_ref: field.type_ref,
         visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
+        has_default: field.has_default,
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
index 0d3a542a439..65580bce4dd 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
@@ -603,9 +603,10 @@ impl ExprCollector<'_> {
                         })
                         .collect();
                     let spread = nfl.spread().map(|s| self.collect_expr(s));
-                    Expr::RecordLit { path, fields, spread }
+                    let ellipsis = nfl.dotdot_token().is_some();
+                    Expr::RecordLit { path, fields, spread, ellipsis }
                 } else {
-                    Expr::RecordLit { path, fields: Box::default(), spread: None }
+                    Expr::RecordLit { path, fields: Box::default(), spread: None, ellipsis: false }
                 };
 
                 self.alloc_expr(record_lit, syntax_ptr)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
index 6ba0bbd61c4..9a8a8c2cd05 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
@@ -398,7 +398,7 @@ impl Printer<'_> {
                     self.print_expr(*expr);
                 }
             }
-            Expr::RecordLit { path, fields, spread } => {
+            Expr::RecordLit { path, fields, spread, ellipsis: _ } => {
                 match path {
                     Some(path) => self.print_path(path),
                     None => w!(self, "�"),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
index 0dcddf162b2..1e2417ecdf3 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
@@ -252,6 +252,7 @@ pub enum Expr {
         path: Option<Box<Path>>,
         fields: Box<[RecordLitField]>,
         spread: Option<ExprId>,
+        ellipsis: bool,
     },
     Field {
         expr: ExprId,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index 79ee3344d25..09fb5f6fd2d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -1006,6 +1006,7 @@ pub struct Field {
     pub name: Name,
     pub type_ref: TypeRefId,
     pub visibility: RawVisibilityId,
+    pub has_default: bool,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index 71848845a84..69a1933079c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -319,8 +319,9 @@ impl<'a> Ctx<'a> {
         };
         let visibility = self.lower_visibility(field);
         let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
+        let has_default = field.expr().is_some();
 
-        Field { name, type_ref, visibility }
+        Field { name, type_ref, visibility, has_default }
     }
 
     fn lower_tuple_field(
@@ -332,7 +333,7 @@ impl<'a> Ctx<'a> {
         let name = Name::new_tuple_field(idx);
         let visibility = self.lower_visibility(field);
         let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
-        Field { name, type_ref, visibility }
+        Field { name, type_ref, visibility, has_default: false }
     }
 
     fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
index 70bf2f13c88..1e765ac78eb 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
@@ -135,7 +135,9 @@ impl Printer<'_> {
                 self.whitespace();
                 w!(self, "{{");
                 self.indented(|this| {
-                    for (idx, Field { name, type_ref, visibility }) in fields.iter().enumerate() {
+                    for (idx, Field { name, type_ref, visibility, has_default: _ }) in
+                        fields.iter().enumerate()
+                    {
                         this.print_attrs_of(
                             AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))),
                             "\n",
@@ -151,7 +153,9 @@ impl Printer<'_> {
             FieldsShape::Tuple => {
                 w!(self, "(");
                 self.indented(|this| {
-                    for (idx, Field { name, type_ref, visibility }) in fields.iter().enumerate() {
+                    for (idx, Field { name, type_ref, visibility, has_default: _ }) in
+                        fields.iter().enumerate()
+                    {
                         this.print_attrs_of(
                             AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))),
                             "\n",
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index 0b5f1319243..d8700e27777 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -547,8 +547,8 @@ pub fn record_literal_missing_fields(
     id: ExprId,
     expr: &Expr,
 ) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> {
-    let (fields, exhaustive) = match expr {
-        Expr::RecordLit { fields, spread, .. } => (fields, spread.is_none()),
+    let (fields, exhaustive, ellipsis) = match expr {
+        Expr::RecordLit { fields, spread, ellipsis, .. } => (fields, spread.is_none(), *ellipsis),
         _ => return None,
     };
 
@@ -563,7 +563,13 @@ pub fn record_literal_missing_fields(
     let missed_fields: Vec<LocalFieldId> = variant_data
         .fields()
         .iter()
-        .filter_map(|(f, d)| if specified_fields.contains(&d.name) { None } else { Some(f) })
+        .filter_map(|(f, d)| {
+            if (ellipsis && d.has_default) || specified_fields.contains(&d.name) {
+                None
+            } else {
+                Some(f)
+            }
+        })
         .collect();
     if missed_fields.is_empty() {
         return None;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
index d74a383f44e..5b6c3cd1524 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
@@ -121,7 +121,7 @@ impl InferenceContext<'_> {
             Expr::Become { expr } => {
                 self.infer_mut_expr(*expr, Mutability::Not);
             }
-            Expr::RecordLit { path: _, fields, spread } => {
+            Expr::RecordLit { path: _, fields, spread, ellipsis: _ } => {
                 self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr).chain(*spread))
             }
             &Expr::Index { base, index } => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 23072011a7b..85e8d172031 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -823,7 +823,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
             }
             Expr::Become { .. } => not_supported!("tail-calls"),
             Expr::Yield { .. } => not_supported!("yield"),
-            Expr::RecordLit { fields, path, spread } => {
+            Expr::RecordLit { fields, path, spread, ellipsis: _ } => {
                 let spread_place = match spread {
                     &Some(it) => {
                         let Some((p, c)) = self.lower_expr_as_place(current, it, true)? else {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
index 938b7182bc9..c495df9daaa 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -846,4 +846,35 @@ pub struct Claims {
         "#,
         );
     }
+
+    #[test]
+    fn default_field_values() {
+        check_diagnostics(
+            r#"
+struct F {
+    field1: i32 = 4,
+    field2: bool,
+}
+
+fn f() {
+    let _f = F {
+        field2: true,
+        ..
+    };
+
+    let _f = F {
+           //^ 💡 error: missing structure fields:
+           //| - field1
+        field2: true,
+    };
+
+    let _f = F {
+           //^ 💡 error: missing structure fields:
+           //| - field2
+        ..
+    };
+}
+"#,
+        );
+    }
 }