Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22433 from dotacow/master
feat(ide-diagnostics): add diagnostics for invalid union patterns (E0784)
Chayim Refael Friedman 9 days ago
parent caa8435 · parent 63fa044 · commit b5da521
-rw-r--r--crates/hir-ty/src/infer.rs8
-rw-r--r--crates/hir-ty/src/infer/pat.rs4
-rw-r--r--crates/hir/src/diagnostics.rs20
-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.rs8
6 files changed, 122 insertions, 2 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 1f6f6f551a..116469a554 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -381,6 +381,14 @@ pub enum InferenceDiagnostic {
#[type_visitable(ignore)]
variant: VariantId,
},
+ UnionPatMustHaveExactlyOneField {
+ #[type_visitable(ignore)]
+ pat: PatId,
+ },
+ UnionPatHasRest {
+ #[type_visitable(ignore)]
+ pat: PatId,
+ },
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 81ba37726c..1e539d24c1 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -1242,10 +1242,10 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
// 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.
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index d99ed37d7e..c551cfac79 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -177,6 +177,8 @@ diagnostics![AnyDiagnostic<'db> ->
ElidedLifetimesInPath,
TypeMustBeKnown<'db>,
UnionExprMustHaveExactlyOneField,
+ UnionPatMustHaveExactlyOneField,
+ UnionPatHasRest,
UnimplementedTrait<'db>,
YieldOutsideCoroutine,
];
@@ -646,6 +648,16 @@ 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 InvalidLhsOfAssignment {
pub lhs: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
}
@@ -944,6 +956,14 @@ 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::FunctionalRecordUpdateOnNonStruct { base_expr } => {
FunctionalRecordUpdateOnNonStruct { base_expr: expr_syntax(base_expr)? }.into()
}
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..9333118719
--- /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..5c229211e1
--- /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 5a14d1bba8..e26e3dbc1d 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -90,6 +90,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;
@@ -551,6 +553,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),