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)
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 8 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/pat.rs | 4 | ||||
| -rw-r--r-- | crates/hir/src/diagnostics.rs | 20 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/union_pat_has_rest.rs | 41 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/union_pat_must_have_exactly_one_field.rs | 43 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/lib.rs | 8 |
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), |