Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22238 from MavenRain/fixme-array-pat-incorrect-length
ide-diagnostics: emit error for mismatched array pattern length
Chayim Refael Friedman 2 weeks ago
parent c25feec · parent 1a6aa1e · commit cfe9d5b
-rw-r--r--crates/hir-ty/src/infer.rs10
-rw-r--r--crates/hir-ty/src/infer/pat.rs14
-rw-r--r--crates/hir/src/diagnostics.rs13
-rw-r--r--crates/ide-diagnostics/src/handlers/mismatched_array_pat_len.rs114
-rw-r--r--crates/ide-diagnostics/src/lib.rs2
5 files changed, 151 insertions, 2 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 09c1325c41..0e307feaa8 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -319,6 +319,16 @@ pub enum InferenceDiagnostic {
#[type_visitable(ignore)]
variant: VariantId,
},
+ MismatchedArrayPatLen {
+ #[type_visitable(ignore)]
+ pat: PatId,
+ #[type_visitable(ignore)]
+ expected: u128,
+ #[type_visitable(ignore)]
+ found: u128,
+ #[type_visitable(ignore)]
+ has_rest: bool,
+ },
PrivateField {
#[type_visitable(ignore)]
expr: ExprId,
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index a7b82dad4f..0b2c7dd745 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -1649,7 +1649,12 @@ https://doc.rust-lang.org/reference/types.html#trait-objects";
return (None, arr_ty);
}
- // FIXME: Emit an error: incorrect length.
+ self.push_diagnostic(InferenceDiagnostic::MismatchedArrayPatLen {
+ pat,
+ expected: len,
+ found: min_len,
+ has_rest: false,
+ });
} else if let Some(pat_len) = len.checked_sub(min_len) {
// The variable-length pattern was there,
// so it has an array type with the remaining elements left as its size...
@@ -1657,7 +1662,12 @@ https://doc.rust-lang.org/reference/types.html#trait-objects";
} else {
// ...however, in this case, there were no remaining elements.
// That is, the slice pattern requires more than the array type offers.
- // FIXME: Emit an error.
+ self.push_diagnostic(InferenceDiagnostic::MismatchedArrayPatLen {
+ pat,
+ expected: len,
+ found: min_len,
+ has_rest: true,
+ });
}
} else if slice.is_none() {
// We have a pattern with a fixed length,
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 3259abb536..168854de74 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -81,6 +81,7 @@ diagnostics![AnyDiagnostic<'db> ->
NonExhaustiveLet,
NonExhaustiveRecordExpr,
NoSuchField,
+ MismatchedArrayPatLen,
PatternArgInExternFn,
PrivateAssocItem,
PrivateField,
@@ -233,6 +234,14 @@ pub struct MismatchedTupleStructPatArgCount {
}
#[derive(Debug)]
+pub struct MismatchedArrayPatLen {
+ pub pat: InFile<ExprOrPatPtr>,
+ pub expected: u128,
+ pub found: u128,
+ pub has_rest: bool,
+}
+
+#[derive(Debug)]
pub struct ExpectedFunction<'db> {
pub call: InFile<ExprOrPatPtr>,
pub found: Type<'db>,
@@ -683,6 +692,10 @@ impl<'db> AnyDiagnostic<'db> {
let private = private.map(|id| Field { id, parent: variant.into() });
NoSuchField { field: expr_or_pat, private, variant }.into()
}
+ &InferenceDiagnostic::MismatchedArrayPatLen { pat, expected, found, has_rest } => {
+ let pat = pat_syntax(pat)?.map(Into::into);
+ MismatchedArrayPatLen { pat, expected, found, has_rest }.into()
+ }
&InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
MismatchedArgCount { call_expr: expr_syntax(call_expr)?, expected, found }.into()
}
diff --git a/crates/ide-diagnostics/src/handlers/mismatched_array_pat_len.rs b/crates/ide-diagnostics/src/handlers/mismatched_array_pat_len.rs
new file mode 100644
index 0000000000..8cae405c92
--- /dev/null
+++ b/crates/ide-diagnostics/src/handlers/mismatched_array_pat_len.rs
@@ -0,0 +1,114 @@
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: mismatched-array-pat-len
+//
+// This diagnostic is triggered when an array pattern's element count does not
+// match the array's declared length.
+pub(crate) fn mismatched_array_pat_len(
+ ctx: &DiagnosticsContext<'_, '_>,
+ d: &hir::MismatchedArrayPatLen,
+) -> Diagnostic {
+ let (code, message) = if d.has_rest {
+ (
+ "E0528",
+ format!(
+ "pattern requires at least {} element{} but array has {}",
+ d.found,
+ if d.found == 1 { "" } else { "s" },
+ d.expected,
+ ),
+ )
+ } else {
+ (
+ "E0527",
+ format!(
+ "pattern requires {} element{} but array has {}",
+ d.found,
+ if d.found == 1 { "" } else { "s" },
+ d.expected,
+ ),
+ )
+ };
+ Diagnostic::new_with_syntax_node_ptr(
+ ctx,
+ DiagnosticCode::RustcHardError(code),
+ message,
+ d.pat.map(Into::into),
+ )
+ .stable()
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::check_diagnostics;
+
+ #[test]
+ fn array_pattern_too_few_elements() {
+ check_diagnostics(
+ r#"
+fn f(arr: [i32; 3]) {
+ let [_a, _b] = arr;
+ //^^^^^^^^ error: pattern requires 2 elements but array has 3
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn array_pattern_too_many_elements() {
+ check_diagnostics(
+ r#"
+fn f(arr: [i32; 2]) {
+ let [_a, _b, _c] = arr;
+ //^^^^^^^^^^^^ error: pattern requires 3 elements but array has 2
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn array_pattern_with_rest_too_short() {
+ check_diagnostics(
+ r#"
+fn f(arr: [i32; 2]) {
+ let [_a, _b, _c, ..] = arr;
+ //^^^^^^^^^^^^^^^^ error: pattern requires at least 3 elements but array has 2
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn array_pattern_with_rest_ok() {
+ check_diagnostics(
+ r#"
+fn f(arr: [i32; 5]) {
+ let [_a, _b, ..] = arr;
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn array_pattern_exact_length_ok() {
+ check_diagnostics(
+ r#"
+fn f(arr: [i32; 3]) {
+ let [_a, _b, _c] = arr;
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn array_pattern_singular_element_uses_singular() {
+ check_diagnostics(
+ r#"
+fn f(arr: [i32; 3]) {
+ let [_a] = arr;
+ //^^^^ error: pattern requires 1 element but array has 3
+}
+"#,
+ );
+ }
+}
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index 1d5811954c..3f803a8c11 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -47,6 +47,7 @@ mod handlers {
pub(crate) mod macro_error;
pub(crate) mod malformed_derive;
pub(crate) mod mismatched_arg_count;
+ pub(crate) mod mismatched_array_pat_len;
pub(crate) mod missing_fields;
pub(crate) mod missing_lifetime;
pub(crate) mod missing_match_arms;
@@ -426,6 +427,7 @@ pub fn semantic_diagnostics(
},
AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d),
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::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d),
AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d),