Skip to content
Merged
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 @@ -482,6 +482,10 @@ pub enum InferenceDiagnostic {
#[type_visitable(ignore)]
kind: ExplicitDropMethodUseKind,
},
MutableRefBinding {
#[type_visitable(ignore)]
pat: PatId,
},
}

#[derive(Debug, PartialEq, Eq, Clone)]
Expand Down
4 changes: 2 additions & 2 deletions crates/hir-ty/src/infer/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -893,14 +893,14 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
let user_bind_annot = BindingMode::from_annotation(binding_data.mode);
let bm = match user_bind_annot {
BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(_) = def_br => {
// Only mention the experimental `mut_ref` feature if if we're in edition 2024 and
// Only mention the experimental `mut_ref` feature if we're in edition 2024 and
// using other experimental matching features compatible with it.
if self.edition.at_least_2024()
&& (self.features.ref_pat_eat_one_layer_2024
|| self.features.ref_pat_eat_one_layer_2024_structural)
{
if !self.features.mut_ref {
// FIXME: Emit an error: binding cannot be both mutable and by-reference.
self.push_diagnostic(InferenceDiagnostic::MutableRefBinding { pat });
}

BindingMode(def_br, Mutability::Mut)
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 @@ -131,6 +131,7 @@ diagnostics![AnyDiagnostic<'db> ->
MissingMatchArms,
MissingUnsafe,
MovedOutOfRef<'db>,
MutableRefBinding,
NeedMut,
NonExhaustiveLet,
NonExhaustiveRecordExpr,
Expand Down Expand Up @@ -633,6 +634,11 @@ pub struct UnimplementedTrait<'db> {
pub root_trait_predicate: Option<crate::TraitPredicate<'db>>,
}

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

impl<'db> AnyDiagnostic<'db> {
pub(crate) fn body_validation_diagnostic(
db: &'db dyn HirDatabase,
Expand Down Expand Up @@ -1070,6 +1076,10 @@ impl<'db> AnyDiagnostic<'db> {
};
ExplicitDropMethodUse { expr_or_path }.into()
}
InferenceDiagnostic::MutableRefBinding { pat } => {
let pat = pat_syntax(*pat)?.map(Into::into);
MutableRefBinding { pat }.into()
}
})
}

Expand Down
64 changes: 64 additions & 0 deletions crates/ide-diagnostics/src/handlers/mutable_ref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};

// Diagnostic: mutable-ref
//
// This diagnostic is triggered when binding is taken that is both mutable and by-reference.
pub(crate) fn mutable_ref_binding(
ctx: &DiagnosticsContext<'_, '_>,
d: &hir::MutableRefBinding,
) -> Diagnostic {
Diagnostic::new_with_syntax_node_ptr(
ctx,
DiagnosticCode::RustcHardError("E0658"),
"bindings cannot be both mutable and by-reference by default in 2024 edition. add experimental #![feature(mut_ref)] for this functionality",
d.pat.map(Into::into),
)
.stable()
}

#[cfg(test)]
mod tests {
use crate::tests::check_diagnostics;

#[test]
fn mutable_ref_binding_missing_feature() {
check_diagnostics(
r#"
//- minicore: option
#![feature(ref_pat_eat_one_layer_2024)]
struct TestStruct {
val: i32
}
fn main() {
let opt_ref = &Some(TestStruct {val: 1});

if let Some(mut x) = opt_ref {
//^^^^^ error: bindings cannot be both mutable and by-reference by default in 2024 edition. add experimental #![feature(mut_ref)] for this functionality
x = &TestStruct{val: 5};
}
}
"#,
);
}

#[test]
fn mutable_ref_binding_with_feature() {
check_diagnostics(
r#"
//- minicore: option
#![feature(ref_pat_eat_one_layer_2024)]
#![feature(mut_ref)]
struct TestStruct {
val: i32
}
fn main() {
let opt_ref = &Some(TestStruct{val: 1});

if let Some(mut x) = opt_ref {
x = &TestStruct{val: 5};
}
}
"#,
);
}
}
2 changes: 2 additions & 0 deletions crates/ide-diagnostics/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ mod handlers {
pub(crate) mod missing_unsafe;
pub(crate) mod moved_out_of_ref;
pub(crate) mod mutability_errors;
pub(crate) mod mutable_ref;
pub(crate) mod no_such_field;
pub(crate) mod non_exhaustive_let;
pub(crate) mod non_exhaustive_record_expr;
Expand Down Expand Up @@ -466,6 +467,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::MutableRefBinding(d) => handlers::mutable_ref::mutable_ref_binding(&ctx, &d),
AnyDiagnostic::NeedMut(d) => match handlers::mutability_errors::need_mut(&ctx, &d) {
Some(it) => it,
None => continue,
Expand Down
Loading