Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/diagnostics/expr.rs')
-rw-r--r--crates/hir-ty/src/diagnostics/expr.rs46
1 files changed, 33 insertions, 13 deletions
diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs
index dd1fc3b36e..4e1bb6f4c5 100644
--- a/crates/hir-ty/src/diagnostics/expr.rs
+++ b/crates/hir-ty/src/diagnostics/expr.rs
@@ -41,7 +41,7 @@ use crate::{
pub(crate) use hir_def::{
LocalFieldId, VariantId,
expr_store::Body,
- hir::{Expr, ExprId, MatchArm, Pat, PatId, Statement},
+ hir::{Expr, ExprId, MatchArm, Pat, PatId, RecordSpread, Statement},
};
pub enum BodyValidationDiagnostic {
@@ -123,7 +123,7 @@ impl<'db> ExprValidator<'db> {
}
for (id, expr) in body.exprs() {
- if let Some((variant, missed_fields, true)) =
+ if let Some((variant, missed_fields)) =
record_literal_missing_fields(db, self.infer, id, expr)
{
self.diagnostics.push(BodyValidationDiagnostic::RecordMissingFields {
@@ -154,7 +154,7 @@ impl<'db> ExprValidator<'db> {
}
for (id, pat) in body.pats() {
- if let Some((variant, missed_fields, true)) =
+ if let Some((variant, missed_fields)) =
record_pattern_missing_fields(db, self.infer, id, pat)
{
self.diagnostics.push(BodyValidationDiagnostic::RecordMissingFields {
@@ -557,9 +557,9 @@ pub fn record_literal_missing_fields(
infer: &InferenceResult,
id: ExprId,
expr: &Expr,
-) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> {
- let (fields, exhaustive) = match expr {
- Expr::RecordLit { fields, spread, .. } => (fields, spread.is_none()),
+) -> Option<(VariantId, Vec<LocalFieldId>)> {
+ let (fields, spread) = match expr {
+ Expr::RecordLit { fields, spread, .. } => (fields, spread),
_ => return None,
};
@@ -571,15 +571,28 @@ pub fn record_literal_missing_fields(
let variant_data = variant_def.fields(db);
let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
+ // don't show missing fields if:
+ // - has ..expr
+ // - or has default value + ..
+ // - or already in code
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 specified_fields.contains(&d.name)
+ || matches!(spread, RecordSpread::Expr(_))
+ || (d.default_value.is_some() && matches!(spread, RecordSpread::FieldDefaults))
+ {
+ None
+ } else {
+ Some(f)
+ }
+ })
.collect();
if missed_fields.is_empty() {
return None;
}
- Some((variant_def, missed_fields, exhaustive))
+ Some((variant_def, missed_fields))
}
pub fn record_pattern_missing_fields(
@@ -587,9 +600,9 @@ pub fn record_pattern_missing_fields(
infer: &InferenceResult,
id: PatId,
pat: &Pat,
-) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> {
- let (fields, exhaustive) = match pat {
- Pat::Record { path: _, args, ellipsis } => (args, !ellipsis),
+) -> Option<(VariantId, Vec<LocalFieldId>)> {
+ let (fields, ellipsis) = match pat {
+ Pat::Record { path: _, args, ellipsis } => (args, *ellipsis),
_ => return None,
};
@@ -601,15 +614,22 @@ pub fn record_pattern_missing_fields(
let variant_data = variant_def.fields(db);
let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
+ // don't show missing fields if:
+ // - in code
+ // - or has ..
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 specified_fields.contains(&d.name) || ellipsis { None } else { Some(f) }
+ },
+ )
.collect();
if missed_fields.is_empty() {
return None;
}
- Some((variant_def, missed_fields, exhaustive))
+ Some((variant_def, missed_fields))
}
fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResult) -> bool {