Unnamed repository; edit this file 'description' to name the repository.
| -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/invalid_range_pat_type.rs | 55 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/lib.rs | 2 |
5 files changed, 72 insertions, 1 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 6a29b2cedb..8f17776d02 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -302,6 +302,10 @@ pub enum InferenceDiagnostic { pat: PatId, found: StoredTy, }, + InvalidRangePatType { + #[type_visitable(ignore)] + pat: PatId, + }, DuplicateField { #[type_visitable(ignore)] field: ExprOrPatId, diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs index f21438647c..8e87d22a45 100644 --- a/crates/hir-ty/src/infer/pat.rs +++ b/crates/hir-ty/src/infer/pat.rs @@ -843,7 +843,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) { // There exists a side that didn't meet our criteria that the end-point // be of a numeric or char type, as checked in `calc_side` above. - // FIXME: Emit an error. + self.push_diagnostic(InferenceDiagnostic::InvalidRangePatType { pat }); return self.types.types.error; } diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index a044f24587..77a17f1c76 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -115,6 +115,7 @@ diagnostics![AnyDiagnostic<'db> -> InvalidCast<'db>, InvalidDeriveTarget, InvalidLhsOfAssignment, + InvalidRangePatType, MacroDefError, MacroError, MacroExpansionParseError, @@ -304,6 +305,11 @@ pub struct ExpectedArrayOrSlicePat<'db> { } #[derive(Debug)] +pub struct InvalidRangePatType { + pub pat: InFile<ExprOrPatPtr>, +} + +#[derive(Debug)] pub struct ExpectedFunction<'db> { pub call: InFile<ExprOrPatPtr>, pub found: Type<'db>, @@ -788,6 +794,10 @@ impl<'db> AnyDiagnostic<'db> { let pat = pat_syntax(*pat)?.map(Into::into); ExpectedArrayOrSlicePat { pat, found: Type::new(db, def, found.as_ref()) }.into() } + &InferenceDiagnostic::InvalidRangePatType { pat } => { + let pat = pat_syntax(pat)?.map(Into::into); + InvalidRangePatType { pat }.into() + } &InferenceDiagnostic::DuplicateField { field: expr, variant } => { let expr_or_pat = match expr { ExprOrPatId::ExprId(expr) => { diff --git a/crates/ide-diagnostics/src/handlers/invalid_range_pat_type.rs b/crates/ide-diagnostics/src/handlers/invalid_range_pat_type.rs new file mode 100644 index 0000000000..465f59559d --- /dev/null +++ b/crates/ide-diagnostics/src/handlers/invalid_range_pat_type.rs @@ -0,0 +1,55 @@ +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; + +// Diagnostic: invalid-range-pat-type +// +// This diagnostic is triggered when a range pattern is used with a type that +// is neither `char` nor numeric. +pub(crate) fn invalid_range_pat_type( + ctx: &DiagnosticsContext<'_, '_>, + d: &hir::InvalidRangePatType, +) -> Diagnostic { + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0029"), + "only `char` and numeric types are allowed in range patterns", + d.pat.map(Into::into), + ) + .stable() +} + +#[cfg(test)] +mod tests { + use crate::tests::check_diagnostics; + + #[test] + fn bool_range_pattern() { + check_diagnostics( + r#" +fn f(x: bool) { + match x { + false..=true => {} + //^^^^^^^^^^^^ error: only `char` and numeric types are allowed in range patterns + } +} +"#, + ); + } + + #[test] + fn numeric_and_char_range_patterns() { + check_diagnostics( + r#" +fn f(x: u8, c: char) { + match x { + 0..=9 => {} + _ => {} + } + match c { + 'a'..='z' => {} + _ => {} + } +} +"#, + ); + } +} diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index 49b3234a11..967b965f51 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -47,6 +47,7 @@ mod handlers { pub(crate) mod invalid_cast; pub(crate) mod invalid_derive_target; pub(crate) mod invalid_lhs_of_assignment; + pub(crate) mod invalid_range_pat_type; pub(crate) mod macro_error; pub(crate) mod malformed_derive; pub(crate) mod mismatched_arg_count; @@ -519,6 +520,7 @@ pub fn semantic_diagnostics( AnyDiagnostic::ElidedLifetimesInPath(d) => handlers::elided_lifetimes_in_path::elided_lifetimes_in_path(&ctx, &d), AnyDiagnostic::GenericDefaultRefersToSelf(d) => handlers::generic_default_refers_to_self::generic_default_refers_to_self(&ctx, &d), AnyDiagnostic::InvalidLhsOfAssignment(d) => handlers::invalid_lhs_of_assignment::invalid_lhs_of_assignment(&ctx, &d), + AnyDiagnostic::InvalidRangePatType(d) => handlers::invalid_range_pat_type::invalid_range_pat_type(&ctx, &d), 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), |