Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22424 from Abusalah0/diag-array-pattern-without-fixed-length
fix: Emit diagnostic for rest array patterns without fixed-length arrays
Laurențiu Nicola 13 days ago
parent 94ea3c8 · parent d41d039 · commit 608f881
-rw-r--r--crates/hir-ty/src/infer.rs4
-rw-r--r--crates/hir-ty/src/infer/pat.rs2
-rw-r--r--crates/hir/src/diagnostics.rs10
-rw-r--r--crates/ide-diagnostics/src/handlers/array_pattern_without_fixed_length.rs46
-rw-r--r--crates/ide-diagnostics/src/lib.rs6
5 files changed, 67 insertions, 1 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index bbb8c99d85..c063d0211f 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -297,6 +297,10 @@ pub enum InferenceDiagnostic {
#[type_visitable(ignore)]
has_rest: bool,
},
+ ArrayPatternWithoutFixedLength {
+ #[type_visitable(ignore)]
+ pat: PatId,
+ },
ExpectedArrayOrSlicePat {
#[type_visitable(ignore)]
pat: PatId,
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index 8703b85e33..f1af8a0b73 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -1701,7 +1701,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects";
// We have a variable-length pattern and don't know the array length.
// This happens if we have e.g.,
// `let [a, b, ..] = arr` where `arr: [T; N]` where `const N: usize`.
- // FIXME: Emit an error: cannot pattern-match on an array without a fixed length.
+ self.push_diagnostic(InferenceDiagnostic::ArrayPatternWithoutFixedLength { pat });
};
// If we get here, we must have emitted an error.
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index d482135812..2d2883eb60 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -101,6 +101,7 @@ macro_rules! diagnostics {
}
diagnostics![AnyDiagnostic<'db> ->
+ ArrayPatternWithoutFixedLength,
AwaitOutsideOfAsync,
BreakOutsideOfLoop,
CannotBeDereferenced<'db>,
@@ -307,6 +308,11 @@ pub struct MismatchedArrayPatLen {
}
#[derive(Debug)]
+pub struct ArrayPatternWithoutFixedLength {
+ pub pat: InFile<ExprOrPatPtr>,
+}
+
+#[derive(Debug)]
pub struct ExpectedArrayOrSlicePat<'db> {
pub pat: InFile<ExprOrPatPtr>,
pub found: Type<'db>,
@@ -836,6 +842,10 @@ impl<'db> AnyDiagnostic<'db> {
let pat = pat_syntax(pat)?.map(Into::into);
MismatchedArrayPatLen { pat, expected, found, has_rest }.into()
}
+ &InferenceDiagnostic::ArrayPatternWithoutFixedLength { pat } => {
+ let pat = pat_syntax(pat)?.map(Into::into);
+ ArrayPatternWithoutFixedLength { pat }.into()
+ }
InferenceDiagnostic::ExpectedArrayOrSlicePat { pat, found } => {
let pat = pat_syntax(*pat)?.map(Into::into);
ExpectedArrayOrSlicePat { pat, found: Type::new(db, def, found.as_ref()) }.into()
diff --git a/crates/ide-diagnostics/src/handlers/array_pattern_without_fixed_length.rs b/crates/ide-diagnostics/src/handlers/array_pattern_without_fixed_length.rs
new file mode 100644
index 0000000000..e7d0868350
--- /dev/null
+++ b/crates/ide-diagnostics/src/handlers/array_pattern_without_fixed_length.rs
@@ -0,0 +1,46 @@
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: array-pattern-without-fixed-length
+//
+// This diagnostic is triggered when a rest array pattern is matched against an
+// array with a non-constant length.
+pub(crate) fn array_pattern_without_fixed_length(
+ ctx: &DiagnosticsContext<'_, '_>,
+ d: &hir::ArrayPatternWithoutFixedLength,
+) -> Diagnostic {
+ Diagnostic::new_with_syntax_node_ptr(
+ ctx,
+ DiagnosticCode::RustcHardError("E0730"),
+ "cannot pattern-match on an array without a fixed length",
+ d.pat.map(Into::into),
+ )
+ .stable()
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::check_diagnostics;
+
+ #[test]
+ fn array_pattern_without_fixed_length() {
+ check_diagnostics(
+ r#"
+fn f<const N: usize>(arr: [u8; N]) {
+ let [_head, _tail @ ..] = arr;
+ //^^^^^^^^^^^^^^^^^^^ error: cannot pattern-match on an array without a fixed length
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn fixed_length_array_pattern_is_ok() {
+ check_diagnostics(
+ r#"
+fn f(arr: [u8; 3]) {
+ let [_head, _tail @ ..] = arr;
+}
+"#,
+ );
+ }
+}
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index 9639772094..18251bc8a2 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -29,6 +29,7 @@
extern crate rustc_driver as _;
mod handlers {
+ pub(crate) mod array_pattern_without_fixed_length;
pub(crate) mod await_outside_of_async;
pub(crate) mod bad_rtn;
pub(crate) mod break_outside_of_loop;
@@ -437,6 +438,11 @@ pub fn semantic_diagnostics(
AnyDiagnostic::CannotBeDereferenced(d) => handlers::cannot_be_dereferenced::cannot_be_dereferenced(&ctx, &d),
AnyDiagnostic::CannotIndexInto(d) => handlers::cannot_index_into::cannot_index_into(&ctx, &d),
AnyDiagnostic::CastToUnsized(d) => handlers::invalid_cast::cast_to_unsized(&ctx, &d),
+ AnyDiagnostic::ArrayPatternWithoutFixedLength(d) => {
+ handlers::array_pattern_without_fixed_length::array_pattern_without_fixed_length(
+ &ctx, &d,
+ )
+ }
AnyDiagnostic::ExpectedArrayOrSlicePat(d) => handlers::expected_array_or_slice_pat::expected_array_or_slice_pat(&ctx, &d),
AnyDiagnostic::ExpectedFunction(d) => handlers::expected_function::expected_function(&ctx, &d),
AnyDiagnostic::FunctionalRecordUpdateOnNonStruct(d) => handlers::functional_record_update_on_non_struct::functional_record_update_on_non_struct(&ctx, &d),