Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-ty/src/diagnostics/expr.rs11
-rw-r--r--crates/hir-ty/src/infer.rs16
-rw-r--r--crates/hir-ty/src/infer/pat.rs12
-rw-r--r--crates/hir/src/diagnostics.rs36
-rw-r--r--crates/ide-diagnostics/src/handlers/record_pat_missing_fields.rs43
-rw-r--r--crates/ide-diagnostics/src/handlers/union_pat_has_rest.rs41
-rw-r--r--crates/ide-diagnostics/src/handlers/union_pat_must_have_exactly_one_field.rs43
-rw-r--r--crates/ide-diagnostics/src/lib.rs12
8 files changed, 200 insertions, 14 deletions
diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs
index 760ebd27e0..e512915ccc 100644
--- a/crates/hir-ty/src/diagnostics/expr.rs
+++ b/crates/hir-ty/src/diagnostics/expr.rs
@@ -158,17 +158,6 @@ impl<'db> ExprValidator<'db> {
}
}
- for (id, pat) in body.pats() {
- if let Some((variant, missed_fields)) =
- record_pattern_missing_fields(db, self.infer, id, pat)
- {
- self.diagnostics.push(BodyValidationDiagnostic::RecordMissingFields {
- record: Either::Right(id),
- variant,
- missed_fields,
- });
- }
- }
}
fn validate_call(
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index c063d0211f..fc1e77efce 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -375,6 +375,22 @@ pub enum InferenceDiagnostic {
#[type_visitable(ignore)]
variant: VariantId,
},
+ UnionPatMustHaveExactlyOneField {
+ #[type_visitable(ignore)]
+ pat: PatId,
+ },
+ UnionPatHasRest {
+ #[type_visitable(ignore)]
+ pat: PatId,
+ },
+ RecordPatMissingFields {
+ #[type_visitable(ignore)]
+ pat: PatId,
+ #[type_visitable(ignore)]
+ variant: VariantId,
+ #[type_visitable(ignore)]
+ missing_fields: Vec<LocalFieldId>,
+ },
FunctionalRecordUpdateOnNonStruct {
#[type_visitable(ignore)]
base_expr: ExprId,
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index f1af8a0b73..e876375cbc 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -1241,13 +1241,19 @@ https://doc.rust-lang.org/reference/types.html#trait-objects";
// Report an error if an incorrect number of fields was specified.
if matches!(variant, VariantId::UnionId(_)) {
if fields.len() != 1 {
- // FIXME: Emit an error, unions can't have more than one field.
+ self.push_diagnostic(InferenceDiagnostic::UnionPatMustHaveExactlyOneField { pat });
}
if has_rest_pat {
- // FIXME: Emit an error, unions can't have a rest pat.
+ self.push_diagnostic(InferenceDiagnostic::UnionPatHasRest { pat });
}
} else if !unmentioned_fields.is_empty() && !has_rest_pat {
- // FIXME: Emit an error.
+ let missing_fields =
+ unmentioned_fields.iter().map(|(field_id, _)| *field_id).collect();
+ self.push_diagnostic(InferenceDiagnostic::RecordPatMissingFields {
+ pat,
+ variant,
+ missing_fields,
+ });
}
}
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 2d2883eb60..77f227b841 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -174,6 +174,9 @@ diagnostics![AnyDiagnostic<'db> ->
ElidedLifetimesInPath,
TypeMustBeKnown<'db>,
UnionExprMustHaveExactlyOneField,
+ UnionPatMustHaveExactlyOneField,
+ UnionPatHasRest,
+ RecordPatMissingFields,
UnimplementedTrait<'db>,
];
@@ -626,6 +629,22 @@ pub struct UnionExprMustHaveExactlyOneField {
}
#[derive(Debug)]
+pub struct UnionPatMustHaveExactlyOneField {
+ pub pat: InFile<ExprOrPatPtr>,
+}
+
+#[derive(Debug)]
+pub struct UnionPatHasRest {
+ pub pat: InFile<ExprOrPatPtr>,
+}
+
+#[derive(Debug)]
+pub struct RecordPatMissingFields {
+ pub pat: InFile<ExprOrPatPtr>,
+ pub missed_fields: Vec<Name>,
+}
+
+#[derive(Debug)]
pub struct InvalidLhsOfAssignment {
pub lhs: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
}
@@ -942,6 +961,23 @@ impl<'db> AnyDiagnostic<'db> {
let pat = pat_syntax(pat)?.map(Into::into);
NonExhaustiveRecordPat { pat, variant: variant.into() }.into()
}
+ &InferenceDiagnostic::UnionPatMustHaveExactlyOneField { pat } => {
+ let pat = pat_syntax(pat)?.map(Into::into);
+ UnionPatMustHaveExactlyOneField { pat }.into()
+ }
+ &InferenceDiagnostic::UnionPatHasRest { pat } => {
+ let pat = pat_syntax(pat)?.map(Into::into);
+ UnionPatHasRest { pat }.into()
+ }
+ InferenceDiagnostic::RecordPatMissingFields { pat, variant, missing_fields } => {
+ let pat = pat_syntax(*pat)?.map(Into::into);
+ let variant_data = variant.fields(db);
+ let missed_fields = missing_fields
+ .iter()
+ .map(|field_id| variant_data.fields()[*field_id].name.clone())
+ .collect();
+ RecordPatMissingFields { pat, missed_fields }.into()
+ }
&InferenceDiagnostic::FunctionalRecordUpdateOnNonStruct { base_expr } => {
FunctionalRecordUpdateOnNonStruct { base_expr: expr_syntax(base_expr)? }.into()
}
diff --git a/crates/ide-diagnostics/src/handlers/record_pat_missing_fields.rs b/crates/ide-diagnostics/src/handlers/record_pat_missing_fields.rs
new file mode 100644
index 0000000000..5ef4b1b045
--- /dev/null
+++ b/crates/ide-diagnostics/src/handlers/record_pat_missing_fields.rs
@@ -0,0 +1,43 @@
+use stdx::format_to;
+
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: record-pat-missing-fields
+//
+// This diagnostic is triggered if a record pattern omits fields without `..`.
+pub(crate) fn record_pat_missing_fields(
+ ctx: &DiagnosticsContext<'_, '_>,
+ d: &hir::RecordPatMissingFields,
+) -> Diagnostic {
+ let mut message = String::from("missing structure fields:\n");
+ for field in &d.missed_fields {
+ format_to!(message, "- {}\n", field.display(ctx.sema.db, ctx.edition));
+ }
+
+ Diagnostic::new_with_syntax_node_ptr(
+ ctx,
+ DiagnosticCode::RustcHardError("E0063"),
+ message,
+ d.pat.map(Into::into),
+ )
+ .stable()
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::check_diagnostics;
+
+ #[test]
+ fn record_pat_missing_fields() {
+ check_diagnostics(
+ r#"
+struct S { foo: i32, bar: () }
+fn baz(s: S) {
+ let S { foo: _ } = s;
+ //^ error: missing structure fields:
+ //| - bar
+}
+"#,
+ );
+ }
+}
diff --git a/crates/ide-diagnostics/src/handlers/union_pat_has_rest.rs b/crates/ide-diagnostics/src/handlers/union_pat_has_rest.rs
new file mode 100644
index 0000000000..03694f621c
--- /dev/null
+++ b/crates/ide-diagnostics/src/handlers/union_pat_has_rest.rs
@@ -0,0 +1,41 @@
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: union-pat-has-rest
+//
+// A union pattern uses `..`.
+pub(crate) fn union_pat_has_rest(
+ ctx: &DiagnosticsContext<'_, '_>,
+ d: &hir::UnionPatHasRest,
+) -> Diagnostic {
+ Diagnostic::new_with_syntax_node_ptr(
+ ctx,
+ DiagnosticCode::RustcHardError("E0784"),
+ "union patterns cannot use `..`",
+ d.pat.map(Into::into),
+ )
+ .stable()
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::check_diagnostics;
+
+ #[test]
+ fn union_pat_has_rest() {
+ check_diagnostics(
+ r#"
+union Bird {
+ pigeon: u8,
+ turtledove: u16,
+}
+
+fn main(bird: Bird) {
+ unsafe {
+ let Bird { pigeon: 0, .. } = bird;
+ // ^^^^^^^^^^^^^^^^^^^^^ error: union patterns cannot use `..`
+ }
+}
+"#,
+ );
+ }
+}
diff --git a/crates/ide-diagnostics/src/handlers/union_pat_must_have_exactly_one_field.rs b/crates/ide-diagnostics/src/handlers/union_pat_must_have_exactly_one_field.rs
new file mode 100644
index 0000000000..f78514cd3c
--- /dev/null
+++ b/crates/ide-diagnostics/src/handlers/union_pat_must_have_exactly_one_field.rs
@@ -0,0 +1,43 @@
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: union-pat-must-have-exactly-one-field
+//
+// A union pattern does not have exactly one field.
+pub(crate) fn union_pat_must_have_exactly_one_field(
+ ctx: &DiagnosticsContext<'_, '_>,
+ d: &hir::UnionPatMustHaveExactlyOneField,
+) -> Diagnostic {
+ Diagnostic::new_with_syntax_node_ptr(
+ ctx,
+ DiagnosticCode::RustcHardError("E0784"),
+ "union patterns should have exactly one field",
+ d.pat.map(Into::into),
+ )
+ .stable()
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::check_diagnostics;
+
+ #[test]
+ fn union_pat_must_have_exactly_one_field() {
+ check_diagnostics(
+ r#"
+union Bird {
+ pigeon: u8,
+ turtledove: u16,
+}
+
+fn main(bird: Bird) {
+ unsafe {
+ let Bird {} = bird;
+ // ^^^^^^^ error: union patterns should have exactly one field
+ let Bird { pigeon: 0, turtledove: 1 } = bird;
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: union patterns should have exactly one field
+ }
+}
+"#,
+ );
+ }
+}
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index 18251bc8a2..d99f71db76 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -59,6 +59,7 @@ mod handlers {
pub(crate) mod mismatched_arg_count;
pub(crate) mod mismatched_array_pat_len;
pub(crate) mod missing_fields;
+ pub(crate) mod record_pat_missing_fields;
pub(crate) mod missing_lifetime;
pub(crate) mod missing_match_arms;
pub(crate) mod missing_unsafe;
@@ -87,6 +88,8 @@ mod handlers {
pub(crate) mod unimplemented_builtin_macro;
pub(crate) mod unimplemented_trait;
pub(crate) mod union_expr_must_have_exactly_one_field;
+ pub(crate) mod union_pat_has_rest;
+ pub(crate) mod union_pat_must_have_exactly_one_field;
pub(crate) mod unreachable_label;
pub(crate) mod unresolved_assoc_item;
pub(crate) mod unresolved_extern_crate;
@@ -472,6 +475,9 @@ pub fn semantic_diagnostics(
AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d),
AnyDiagnostic::MismatchedArrayPatLen(d) => handlers::mismatched_array_pat_len::mismatched_array_pat_len(&ctx, &d),
AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d),
+ AnyDiagnostic::RecordPatMissingFields(d) => {
+ handlers::record_pat_missing_fields::record_pat_missing_fields(&ctx, &d)
+ }
AnyDiagnostic::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d),
AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d),
AnyDiagnostic::MovedOutOfRef(d) => handlers::moved_out_of_ref::moved_out_of_ref(&ctx, &d),
@@ -544,6 +550,12 @@ pub fn semantic_diagnostics(
AnyDiagnostic::TypeMustBeKnown(d) => handlers::type_must_be_known::type_must_be_known(&ctx, &d),
AnyDiagnostic::PatternArgInExternFn(d) => handlers::pattern_arg_in_extern_fn::pattern_arg_in_extern_fn(&ctx, &d),
AnyDiagnostic::UnionExprMustHaveExactlyOneField(d) => handlers::union_expr_must_have_exactly_one_field::union_expr_must_have_exactly_one_field(&ctx, &d),
+ AnyDiagnostic::UnionPatMustHaveExactlyOneField(d) => {
+ handlers::union_pat_must_have_exactly_one_field::union_pat_must_have_exactly_one_field(&ctx, &d)
+ }
+ AnyDiagnostic::UnionPatHasRest(d) => {
+ handlers::union_pat_has_rest::union_pat_has_rest(&ctx, &d)
+ }
AnyDiagnostic::UnimplementedTrait(d) => handlers::unimplemented_trait::unimplemented_trait(&ctx, &d),
AnyDiagnostic::FruInDestructuringAssignment(d) => handlers::fru_in_destructuring_assignment::fru_in_destructuring_assignment(&ctx, &d),
AnyDiagnostic::ExplicitDropMethodUse(d) => handlers::explicit_drop_method_use::explicit_drop_method_use(&ctx, &d),