Unnamed repository; edit this file 'description' to name the repository.
feat: add diagnostic for E0596
WaterWhisperer 7 weeks ago
parent b48cc10 · commit de60e47
-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/cannot_borrow_as_mutable.rs37
-rw-r--r--crates/ide-diagnostics/src/lib.rs2
5 files changed, 54 insertions, 1 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 2df2789a2e..6179d8dcf8 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -405,6 +405,10 @@ pub enum InferenceDiagnostic {
expr: ExprId,
found: StoredTy,
},
+ CannotBorrowAsMutable {
+ #[type_visitable(ignore)]
+ pat: PatId,
+ },
CannotImplicitlyDerefTraitObject {
#[type_visitable(ignore)]
pat: PatId,
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index c36c29d6c7..543de847cd 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -916,7 +916,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
if matches!(bm.0, ByRef::Yes(Mutability::Mut))
&& let MutblCap::WeaklyNot = pat_info.max_ref_mutbl
{
- // FIXME: Emit an error: cannot borrow as mutable inside an `&` pattern.
+ self.push_diagnostic(InferenceDiagnostic::CannotBorrowAsMutable { pat });
}
// ...and store it in a side table:
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index f3188c9aad..edd24442c4 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -104,6 +104,7 @@ diagnostics![AnyDiagnostic<'db> ->
AwaitOutsideOfAsync,
BreakOutsideOfLoop,
CannotBeDereferenced<'db>,
+ CannotBorrowAsMutable,
CannotImplicitlyDerefTraitObject<'db>,
CannotIndexInto<'db>,
CastToUnsized<'db>,
@@ -336,6 +337,11 @@ pub struct CannotBeDereferenced<'db> {
}
#[derive(Debug)]
+pub struct CannotBorrowAsMutable {
+ pub pat: InFile<ExprOrPatPtr>,
+}
+
+#[derive(Debug)]
pub struct CannotImplicitlyDerefTraitObject<'db> {
pub pat: InFile<ExprOrPatPtr>,
pub found: Type<'db>,
@@ -980,6 +986,10 @@ impl<'db> AnyDiagnostic<'db> {
let expr = expr_syntax(*expr)?;
CannotBeDereferenced { expr, found: new_ty(found.as_ref()) }.into()
}
+ InferenceDiagnostic::CannotBorrowAsMutable { pat } => {
+ let pat = pat_syntax(*pat)?.map(Into::into);
+ CannotBorrowAsMutable { pat }.into()
+ }
InferenceDiagnostic::CannotImplicitlyDerefTraitObject { pat, found } => {
let pat = pat_syntax(*pat)?.map(Into::into);
CannotImplicitlyDerefTraitObject { pat, found: new_ty(found.as_ref()) }.into()
diff --git a/crates/ide-diagnostics/src/handlers/cannot_borrow_as_mutable.rs b/crates/ide-diagnostics/src/handlers/cannot_borrow_as_mutable.rs
new file mode 100644
index 0000000000..f1ae2c4203
--- /dev/null
+++ b/crates/ide-diagnostics/src/handlers/cannot_borrow_as_mutable.rs
@@ -0,0 +1,37 @@
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: cannot-borrow-as-mutable
+//
+// This diagnostic is triggered when a binding tries to mutably borrow through
+// an `&` pattern.
+pub(crate) fn cannot_borrow_as_mutable(
+ ctx: &DiagnosticsContext<'_, '_>,
+ d: &hir::CannotBorrowAsMutable,
+) -> Diagnostic {
+ Diagnostic::new_with_syntax_node_ptr(
+ ctx,
+ DiagnosticCode::RustcHardError("E0596"),
+ "cannot borrow as mutable inside an `&` pattern",
+ d.pat.map(Into::into),
+ )
+ .stable()
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::check_diagnostics;
+
+ #[test]
+ fn cannot_borrow_as_mutable_inside_shared_ref_pattern() {
+ check_diagnostics(
+ r#"
+#![feature(ref_pat_eat_one_layer_2024)]
+
+fn main() {
+ let &ref mut _x = &mut 0;
+ //^^^^^^^^^^ error: cannot borrow as mutable inside an `&` pattern
+}
+"#,
+ );
+ }
+}
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index aec68b55c7..18adc3e1f6 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -34,6 +34,7 @@ mod handlers {
pub(crate) mod bad_rtn;
pub(crate) mod break_outside_of_loop;
pub(crate) mod cannot_be_dereferenced;
+ pub(crate) mod cannot_borrow_as_mutable;
pub(crate) mod cannot_implicitly_deref_trait_object;
pub(crate) mod cannot_index_into;
pub(crate) mod duplicate_field;
@@ -437,6 +438,7 @@ pub fn semantic_diagnostics(
let d = match diag {
AnyDiagnostic::AwaitOutsideOfAsync(d) => handlers::await_outside_of_async::await_outside_of_async(&ctx, &d),
AnyDiagnostic::CannotBeDereferenced(d) => handlers::cannot_be_dereferenced::cannot_be_dereferenced(&ctx, &d),
+ AnyDiagnostic::CannotBorrowAsMutable(d) => handlers::cannot_borrow_as_mutable::cannot_borrow_as_mutable(&ctx, &d),
AnyDiagnostic::CannotImplicitlyDerefTraitObject(d) => handlers::cannot_implicitly_deref_trait_object::cannot_implicitly_deref_trait_object(&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),