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
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 4 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/pat.rs | 2 | ||||
| -rw-r--r-- | crates/hir/src/diagnostics.rs | 10 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/array_pattern_without_fixed_length.rs | 46 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/lib.rs | 6 |
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), |