Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/hir-ty/src/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,10 @@ pub enum InferenceDiagnostic {
expr: ExprId,
found: StoredTy,
},
MutRefInImmRefPat {
#[type_visitable(ignore)]
pat: PatId,
},
CannotImplicitlyDerefTraitObject {
#[type_visitable(ignore)]
pat: PatId,
Expand Down
2 changes: 1 addition & 1 deletion crates/hir-ty/src/infer/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::MutRefInImmRefPat { pat });
}

// ...and store it in a side table:
Expand Down
10 changes: 10 additions & 0 deletions crates/hir/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ diagnostics![AnyDiagnostic<'db> ->
MissingMatchArms,
MissingUnsafe,
MovedOutOfRef<'db>,
MutRefInImmRefPat,
MutableRefBinding,
NeedMut,
NonExhaustiveLet,
Expand Down Expand Up @@ -335,6 +336,11 @@ pub struct CannotBeDereferenced<'db> {
pub found: Type<'db>,
}

#[derive(Debug)]
pub struct MutRefInImmRefPat {
pub pat: InFile<ExprOrPatPtr>,
}

#[derive(Debug)]
pub struct CannotImplicitlyDerefTraitObject<'db> {
pub pat: InFile<ExprOrPatPtr>,
Expand Down Expand Up @@ -980,6 +986,10 @@ impl<'db> AnyDiagnostic<'db> {
let expr = expr_syntax(*expr)?;
CannotBeDereferenced { expr, found: new_ty(found.as_ref()) }.into()
}
InferenceDiagnostic::MutRefInImmRefPat { pat } => {
let pat = pat_syntax(*pat)?.map(Into::into);
MutRefInImmRefPat { pat }.into()
}
InferenceDiagnostic::CannotImplicitlyDerefTraitObject { pat, found } => {
let pat = pat_syntax(*pat)?.map(Into::into);
CannotImplicitlyDerefTraitObject { pat, found: new_ty(found.as_ref()) }.into()
Expand Down
37 changes: 37 additions & 0 deletions crates/ide-diagnostics/src/handlers/mut_ref_in_imm_ref_pat.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};

// Diagnostic: mut-ref-in-imm-ref-pat
//
// This diagnostic is triggered when a binding tries to mutably borrow through
// an `&` pattern.
pub(crate) fn mut_ref_in_imm_ref_pat(
ctx: &DiagnosticsContext<'_, '_>,
d: &hir::MutRefInImmRefPat,
) -> 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 mut_ref_in_imm_ref_pat() {
check_diagnostics(
r#"
#![feature(ref_pat_eat_one_layer_2024)]
Comment thread
ChayimFriedman2 marked this conversation as resolved.

fn main() {
let &ref mut _x = &mut 0;
//^^^^^^^^^^ error: cannot borrow as mutable inside an `&` pattern
}
"#,
);
}
}
2 changes: 2 additions & 0 deletions crates/ide-diagnostics/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ mod handlers {
pub(crate) mod missing_match_arms;
pub(crate) mod missing_unsafe;
pub(crate) mod moved_out_of_ref;
pub(crate) mod mut_ref_in_imm_ref_pat;
pub(crate) mod mutability_errors;
pub(crate) mod mutable_ref;
pub(crate) mod no_such_field;
Expand Down Expand Up @@ -477,6 +478,7 @@ pub fn semantic_diagnostics(
AnyDiagnostic::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d),
AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d),
AnyDiagnostic::MovedOutOfRef(d) => handlers::moved_out_of_ref::moved_out_of_ref(&ctx, &d),
AnyDiagnostic::MutRefInImmRefPat(d) => handlers::mut_ref_in_imm_ref_pat::mut_ref_in_imm_ref_pat(&ctx, &d),
AnyDiagnostic::MutableRefBinding(d) => handlers::mutable_ref::mutable_ref_binding(&ctx, &d),
AnyDiagnostic::NeedMut(d) => match handlers::mutability_errors::need_mut(&ctx, &d) {
Some(it) => it,
Expand Down
Loading