Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-diagnostics/src/handlers/mutability_errors.rs')
-rw-r--r--crates/ide-diagnostics/src/handlers/mutability_errors.rs474
1 files changed, 461 insertions, 13 deletions
diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index 96470265d1..f61460e317 100644
--- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -18,7 +18,8 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Diagno
let use_range = d.span.value.text_range();
for source in d.local.sources(ctx.sema.db) {
let Some(ast) = source.name() else { continue };
- edit_builder.insert(ast.syntax().text_range().start(), "mut ".to_string());
+ // FIXME: macros
+ edit_builder.insert(ast.value.syntax().text_range().start(), "mut ".to_string());
}
let edit = edit_builder.finish();
Some(vec![fix(
@@ -30,7 +31,10 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Diagno
})();
Diagnostic::new(
"need-mut",
- format!("cannot mutate immutable variable `{}`", d.local.name(ctx.sema.db)),
+ format!(
+ "cannot mutate immutable variable `{}`",
+ d.local.name(ctx.sema.db).display(ctx.sema.db)
+ ),
ctx.sema.diagnostics_display_range(d.span.clone()).range,
)
.with_fixes(fixes)
@@ -340,6 +344,7 @@ fn main() {
fn regression_14310() {
check_diagnostics(
r#"
+ //- minicore: copy, builtin_impls
fn clone(mut i: &!) -> ! {
//^^^^^ 💡 weak: variable does not need to be mutable
*i
@@ -349,6 +354,32 @@ fn main() {
}
#[test]
+ fn match_closure_capture() {
+ check_diagnostics(
+ r#"
+//- minicore: option
+fn main() {
+ let mut v = &mut Some(2);
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ let _ = || match v {
+ Some(k) => {
+ *k = 5;
+ }
+ None => {}
+ };
+ let v = &mut Some(2);
+ let _ = || match v {
+ //^ 💡 error: cannot mutate immutable variable `v`
+ ref mut k => {
+ *k = &mut Some(5);
+ }
+ };
+}
+"#,
+ );
+ }
+
+ #[test]
fn match_bindings() {
check_diagnostics(
r#"
@@ -368,7 +399,7 @@ fn main() {
#[test]
fn mutation_in_dead_code() {
// This one is interesting. Dead code is not represented at all in the MIR, so
- // there would be no mutablility error for locals in dead code. Rustc tries to
+ // there would be no mutability error for locals in dead code. Rustc tries to
// not emit `unused_mut` in this case, but since it works without `mut`, and
// special casing it is not trivial, we emit it.
check_diagnostics(
@@ -485,6 +516,38 @@ fn main() {
);
check_diagnostics(
r#"
+fn check(_: i32) -> bool {
+ false
+}
+fn main() {
+ loop {
+ let x = 1;
+ if check(x) {
+ break;
+ }
+ let y = (1, 2);
+ if check(y.1) {
+ return;
+ }
+ let z = (1, 2);
+ match z {
+ (k @ 5, ref mut t) if { continue; } => {
+ //^^^^^^^^^ 💡 error: cannot mutate immutable variable `z`
+ *t = 5;
+ }
+ _ => {
+ let y = (1, 2);
+ if check(y.1) {
+ return;
+ }
+ }
+ }
+ }
+}
+"#,
+ );
+ check_diagnostics(
+ r#"
fn f(_: i32) {}
fn main() {
loop {
@@ -546,13 +609,35 @@ fn f(x: i32) {
}
"#,
);
+ check_diagnostics(
+ r#"
+fn f((x, y): (i32, i32)) {
+ let t = [0; 2];
+ x = 5;
+ //^^^^^ 💡 error: cannot mutate immutable variable `x`
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn no_diagnostics_in_case_of_multiple_bounds() {
+ check_diagnostics(
+ r#"
+fn f() {
+ let (b, a, b) = (2, 3, 5);
+ a = 8;
+ //^^^^^ 💡 error: cannot mutate immutable variable `a`
+}
+"#,
+ );
}
#[test]
fn for_loop() {
check_diagnostics(
r#"
-//- minicore: iterators
+//- minicore: iterators, copy
fn f(x: [(i32, u8); 10]) {
for (a, mut b) in x {
//^^^^^ 💡 weak: variable does not need to be mutable
@@ -565,8 +650,96 @@ fn f(x: [(i32, u8); 10]) {
}
#[test]
+ fn while_let() {
+ check_diagnostics(
+ r#"
+//- minicore: iterators, copy
+fn f(x: [(i32, u8); 10]) {
+ let mut it = x.into_iter();
+ while let Some((a, mut b)) = it.next() {
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ while let Some((c, mut d)) = it.next() {
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ a = 2;
+ //^^^^^ 💡 error: cannot mutate immutable variable `a`
+ c = 2;
+ //^^^^^ 💡 error: cannot mutate immutable variable `c`
+ }
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn index() {
+ check_diagnostics(
+ r#"
+//- minicore: coerce_unsized, index, slice
+fn f() {
+ let x = [1, 2, 3];
+ x[2] = 5;
+ //^^^^^^^^ 💡 error: cannot mutate immutable variable `x`
+ let x = &mut x;
+ //^^^^^^ 💡 error: cannot mutate immutable variable `x`
+ let mut x = x;
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ x[2] = 5;
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn overloaded_index() {
+ check_diagnostics(
+ r#"
+//- minicore: index
+use core::ops::{Index, IndexMut};
+
+struct Foo;
+impl Index<usize> for Foo {
+ type Output = (i32, u8);
+ fn index(&self, index: usize) -> &(i32, u8) {
+ &(5, 2)
+ }
+}
+impl IndexMut<usize> for Foo {
+ fn index_mut(&mut self, index: usize) -> &mut (i32, u8) {
+ &mut (5, 2)
+ }
+}
+fn f() {
+ let mut x = Foo;
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ let y = &x[2];
+ let x = Foo;
+ let y = &mut x[2];
+ //^💡 error: cannot mutate immutable variable `x`
+ let mut x = &mut Foo;
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ let y: &mut (i32, u8) = &mut x[2];
+ let x = Foo;
+ let ref mut y = x[7];
+ //^ 💡 error: cannot mutate immutable variable `x`
+ let (ref mut y, _) = x[3];
+ //^ 💡 error: cannot mutate immutable variable `x`
+ match x[10] {
+ //^ 💡 error: cannot mutate immutable variable `x`
+ (ref y, _) => (),
+ (_, ref mut y) => (),
+ }
+ let mut x = Foo;
+ let mut i = 5;
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ let y = &mut x[i];
+}
+"#,
+ );
+ }
+
+ #[test]
fn overloaded_deref() {
- // FIXME: check for false negative
check_diagnostics(
r#"
//- minicore: deref_mut
@@ -574,22 +747,36 @@ use core::ops::{Deref, DerefMut};
struct Foo;
impl Deref for Foo {
- type Target = i32;
- fn deref(&self) -> &i32 {
- &5
+ type Target = (i32, u8);
+ fn deref(&self) -> &(i32, u8) {
+ &(5, 2)
}
}
impl DerefMut for Foo {
- fn deref_mut(&mut self) -> &mut i32 {
- &mut 5
+ fn deref_mut(&mut self) -> &mut (i32, u8) {
+ &mut (5, 2)
}
}
fn f() {
- let x = Foo;
+ let mut x = Foo;
+ //^^^^^ 💡 weak: variable does not need to be mutable
let y = &*x;
let x = Foo;
- let mut x = Foo;
- let y: &mut i32 = &mut x;
+ let y = &mut *x;
+ //^^ 💡 error: cannot mutate immutable variable `x`
+ let x = Foo;
+ let x = Foo;
+ let y: &mut (i32, u8) = &mut x;
+ //^^^^^^ 💡 error: cannot mutate immutable variable `x`
+ let ref mut y = *x;
+ //^^ 💡 error: cannot mutate immutable variable `x`
+ let (ref mut y, _) = *x;
+ //^^ 💡 error: cannot mutate immutable variable `x`
+ match *x {
+ //^^ 💡 error: cannot mutate immutable variable `x`
+ (ref y, _) => (),
+ (_, ref mut y) => (),
+ }
}
"#,
);
@@ -632,6 +819,267 @@ fn f(inp: (Foo, Foo, Foo, Foo)) {
}
#[test]
+ // FIXME: We should have tests for `is_ty_uninhabited_from`
+ fn regression_14421() {
+ check_diagnostics(
+ r#"
+pub enum Tree {
+ Node(TreeNode),
+ Leaf(TreeLeaf),
+}
+
+struct Box<T>(&T);
+
+pub struct TreeNode {
+ pub depth: usize,
+ pub children: [Box<Tree>; 8]
+}
+
+pub struct TreeLeaf {
+ pub depth: usize,
+ pub data: u8
+}
+
+pub fn test() {
+ let mut tree = Tree::Leaf(
+ //^^^^^^^^ 💡 weak: variable does not need to be mutable
+ TreeLeaf {
+ depth: 0,
+ data: 0
+ }
+ );
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn fn_traits() {
+ check_diagnostics(
+ r#"
+//- minicore: fn
+fn fn_ref(mut x: impl Fn(u8) -> u8) -> u8 {
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ x(2)
+}
+fn fn_mut(x: impl FnMut(u8) -> u8) -> u8 {
+ x(2)
+ //^ 💡 error: cannot mutate immutable variable `x`
+}
+fn fn_borrow_mut(mut x: &mut impl FnMut(u8) -> u8) -> u8 {
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ x(2)
+}
+fn fn_once(mut x: impl FnOnce(u8) -> u8) -> u8 {
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ x(2)
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn closure() {
+ // FIXME: Diagnostic spans are inconsistent inside and outside closure
+ check_diagnostics(
+ r#"
+ //- minicore: copy, fn
+ struct X;
+
+ impl X {
+ fn mutate(&mut self) {}
+ }
+
+ fn f() {
+ let x = 5;
+ let closure1 = || { x = 2; };
+ //^ 💡 error: cannot mutate immutable variable `x`
+ let _ = closure1();
+ //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
+ let closure2 = || { x = x; };
+ //^ 💡 error: cannot mutate immutable variable `x`
+ let closure3 = || {
+ let x = 2;
+ x = 5;
+ //^^^^^ 💡 error: cannot mutate immutable variable `x`
+ x
+ };
+ let x = X;
+ let closure4 = || { x.mutate(); };
+ //^ 💡 error: cannot mutate immutable variable `x`
+ }
+ "#,
+ );
+ check_diagnostics(
+ r#"
+ //- minicore: copy, fn
+ fn f() {
+ let mut x = 5;
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ let mut y = 2;
+ y = 7;
+ let closure = || {
+ let mut z = 8;
+ z = 3;
+ let mut k = z;
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ };
+ }
+ "#,
+ );
+ check_diagnostics(
+ r#"
+//- minicore: copy, fn
+fn f() {
+ let closure = || {
+ || {
+ || {
+ let x = 2;
+ || { || { x = 5; } }
+ //^ 💡 error: cannot mutate immutable variable `x`
+ }
+ }
+ };
+}
+ "#,
+ );
+ check_diagnostics(
+ r#"
+//- minicore: copy, fn
+fn f() {
+ struct X;
+ let mut x = X;
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ let c1 = || x;
+ let mut x = X;
+ let c2 = || { x = X; x };
+ let mut x = X;
+ let c2 = move || { x = X; };
+}
+ "#,
+ );
+ check_diagnostics(
+ r#"
+ //- minicore: copy, fn, deref_mut
+ struct X(i32, i64);
+
+ fn f() {
+ let mut x = &mut 5;
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ let closure1 = || { *x = 2; };
+ let _ = closure1();
+ //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
+ let mut x = &mut 5;
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ let closure1 = || { *x = 2; &x; };
+ let _ = closure1();
+ //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
+ let mut x = &mut 5;
+ let closure1 = || { *x = 2; &x; x = &mut 3; };
+ let _ = closure1();
+ //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
+ let mut x = &mut 5;
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ let closure1 = move || { *x = 2; };
+ let _ = closure1();
+ //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
+ let mut x = &mut X(1, 2);
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ let closure1 = || { x.0 = 2; };
+ let _ = closure1();
+ //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
+ }
+ "#,
+ );
+ }
+
+ #[test]
+ fn slice_pattern() {
+ check_diagnostics(
+ r#"
+//- minicore: coerce_unsized, deref_mut, slice, copy
+fn x(t: &[u8]) {
+ match t {
+ &[a, mut b] | &[a, _, mut b] => {
+ //^^^^^ 💡 weak: variable does not need to be mutable
+
+ a = 2;
+ //^^^^^ 💡 error: cannot mutate immutable variable `a`
+
+ }
+ _ => {}
+ }
+}
+ "#,
+ );
+ }
+
+ #[test]
+ fn boxes() {
+ check_diagnostics(
+ r#"
+//- minicore: coerce_unsized, deref_mut, slice
+use core::ops::{Deref, DerefMut};
+use core::{marker::Unsize, ops::CoerceUnsized};
+
+#[lang = "owned_box"]
+pub struct Box<T: ?Sized> {
+ inner: *mut T,
+}
+impl<T> Box<T> {
+ fn new(t: T) -> Self {
+ #[rustc_box]
+ Box::new(t)
+ }
+}
+
+impl<T: ?Sized> Deref for Box<T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ &**self
+ }
+}
+
+impl<T: ?Sized> DerefMut for Box<T> {
+ fn deref_mut(&mut self) -> &mut T {
+ &mut **self
+ }
+}
+
+fn f() {
+ let x = Box::new(5);
+ x = Box::new(7);
+ //^^^^^^^^^^^^^^^ 💡 error: cannot mutate immutable variable `x`
+ let x = Box::new(5);
+ *x = 7;
+ //^^^^^^ 💡 error: cannot mutate immutable variable `x`
+ let mut y = Box::new(5);
+ //^^^^^ 💡 weak: variable does not need to be mutable
+ *x = *y;
+ //^^^^^^^ 💡 error: cannot mutate immutable variable `x`
+ let x = Box::new(5);
+ let closure = || *x = 2;
+ //^ 💡 error: cannot mutate immutable variable `x`
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn allow_unused_mut_for_identifiers_starting_with_underline() {
+ check_diagnostics(
+ r#"
+fn f(_: i32) {}
+fn main() {
+ let mut _x = 2;
+ f(_x);
+}
+"#,
+ );
+ }
+
+ #[test]
fn respect_allow_unused_mut() {
// FIXME: respect
check_diagnostics(