ide_diagnostics/handlers/
mutability_errors.rs

1use hir::db::ExpandDatabase;
2use ide_db::source_change::SourceChange;
3use ide_db::text_edit::TextEdit;
4use syntax::{AstNode, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, T, ast};
5
6use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, fix};
7
8// Diagnostic: need-mut
9//
10// This diagnostic is triggered on mutating an immutable variable.
11pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option<Diagnostic> {
12    let root = ctx.sema.db.parse_or_expand(d.span.file_id);
13    let node = d.span.value.to_node(&root);
14    let mut span = d.span;
15    if let Some(parent) = node.parent()
16        && ast::BinExpr::can_cast(parent.kind())
17    {
18        // In case of an assignment, the diagnostic is provided on the variable name.
19        // We want to expand it to include the whole assignment, but only when this
20        // is an ordinary assignment, not a destructuring assignment. So, the direct
21        // parent is an assignment expression.
22        span = d.span.with_value(SyntaxNodePtr::new(&parent));
23    };
24
25    let fixes = (|| {
26        if d.local.is_ref(ctx.sema.db) {
27            // There is no simple way to add `mut` to `ref x` and `ref mut x`
28            return None;
29        }
30        let file_id = span.file_id.file_id()?;
31        let mut edit_builder = TextEdit::builder();
32        let use_range = span.value.text_range();
33        for source in d.local.sources(ctx.sema.db) {
34            let Some(ast) = source.name() else { continue };
35            // FIXME: macros
36            edit_builder.insert(ast.value.syntax().text_range().start(), "mut ".to_owned());
37        }
38        let edit = edit_builder.finish();
39        Some(vec![fix(
40            "add_mut",
41            "Change it to be mutable",
42            SourceChange::from_text_edit(file_id.file_id(ctx.sema.db), edit),
43            use_range,
44        )])
45    })();
46
47    Some(
48        Diagnostic::new_with_syntax_node_ptr(
49            ctx,
50            // FIXME: `E0384` is not the only error that this diagnostic handles
51            DiagnosticCode::RustcHardError("E0384"),
52            format!(
53                "cannot mutate immutable variable `{}`",
54                d.local.name(ctx.sema.db).display(ctx.sema.db, ctx.edition)
55            ),
56            span,
57        )
58        .stable()
59        .with_fixes(fixes),
60    )
61}
62
63// Diagnostic: unused-mut
64//
65// This diagnostic is triggered when a mutable variable isn't actually mutated.
66pub(crate) fn unused_mut(ctx: &DiagnosticsContext<'_>, d: &hir::UnusedMut) -> Option<Diagnostic> {
67    let ast = d.local.primary_source(ctx.sema.db).syntax_ptr();
68    let fixes = (|| {
69        let file_id = ast.file_id.file_id()?;
70        let mut edit_builder = TextEdit::builder();
71        let use_range = ast.value.text_range();
72        for source in d.local.sources(ctx.sema.db) {
73            let ast = source.syntax();
74            let Some(mut_token) = token(ast, T![mut]) else { continue };
75            edit_builder.delete(mut_token.text_range());
76            if let Some(token) = mut_token.next_token()
77                && token.kind() == SyntaxKind::WHITESPACE
78            {
79                edit_builder.delete(token.text_range());
80            }
81        }
82        let edit = edit_builder.finish();
83        Some(vec![fix(
84            "remove_mut",
85            "Remove unnecessary `mut`",
86            SourceChange::from_text_edit(file_id.file_id(ctx.sema.db), edit),
87            use_range,
88        )])
89    })();
90    let ast = d.local.primary_source(ctx.sema.db).syntax_ptr();
91    Some(
92        Diagnostic::new_with_syntax_node_ptr(
93            ctx,
94            DiagnosticCode::RustcLint("unused_mut"),
95            "variable does not need to be mutable",
96            ast,
97        )
98        // Not supporting `#[allow(unused_mut)]` in proc macros leads to false positive, hence not stable.
99        .with_fixes(fixes),
100    )
101}
102
103pub(super) fn token(parent: &SyntaxNode, kind: SyntaxKind) -> Option<SyntaxToken> {
104    parent.children_with_tokens().filter_map(|it| it.into_token()).find(|it| it.kind() == kind)
105}
106
107#[cfg(test)]
108mod tests {
109    use crate::tests::{check_diagnostics, check_diagnostics_with_disabled, check_fix};
110
111    #[test]
112    fn unused_mut_simple() {
113        check_diagnostics(
114            r#"
115fn f(_: i32) {}
116fn main() {
117    let mut x = 2;
118      //^^^^^ 💡 warn: variable does not need to be mutable
119    f(x);
120}
121"#,
122        );
123    }
124
125    #[test]
126    fn no_false_positive_simple() {
127        check_diagnostics(
128            r#"
129fn f(_: i32) {}
130fn main() {
131    let x = 2;
132    f(x);
133}
134"#,
135        );
136        check_diagnostics(
137            r#"
138fn f(_: i32) {}
139fn main() {
140    let mut x = 2;
141    x = 5;
142    f(x);
143}
144"#,
145        );
146    }
147
148    #[test]
149    fn multiple_errors_for_single_variable() {
150        check_diagnostics(
151            r#"
152fn f(_: i32) {}
153fn main() {
154    let x = 2;
155    x = 10;
156  //^^^^^^ 💡 error: cannot mutate immutable variable `x`
157    x = 5;
158  //^^^^^ 💡 error: cannot mutate immutable variable `x`
159    &mut x;
160  //^^^^^^ 💡 error: cannot mutate immutable variable `x`
161    f(x);
162}
163"#,
164        );
165    }
166
167    #[test]
168    fn unused_mut_fix() {
169        check_fix(
170            r#"
171fn f(_: i32) {}
172fn main() {
173    let mu$0t x = 2;
174    f(x);
175}
176"#,
177            r#"
178fn f(_: i32) {}
179fn main() {
180    let x = 2;
181    f(x);
182}
183"#,
184        );
185        check_fix(
186            r#"
187fn f(_: i32) {}
188fn main() {
189    let ((mu$0t x, _) | (_, mut x)) = (2, 3);
190    f(x);
191}
192"#,
193            r#"
194fn f(_: i32) {}
195fn main() {
196    let ((x, _) | (_, x)) = (2, 3);
197    f(x);
198}
199"#,
200        );
201    }
202
203    #[test]
204    fn need_mut_fix() {
205        check_fix(
206            r#"
207fn f(_: i32) {}
208fn main() {
209    let x = 2;
210    x$0 = 5;
211    f(x);
212}
213"#,
214            r#"
215fn f(_: i32) {}
216fn main() {
217    let mut x = 2;
218    x = 5;
219    f(x);
220}
221"#,
222        );
223        check_fix(
224            r#"
225fn f(_: i32) {}
226fn main() {
227    let ((x, _) | (_, x)) = (2, 3);
228    x =$0 4;
229    f(x);
230}
231"#,
232            r#"
233fn f(_: i32) {}
234fn main() {
235    let ((mut x, _) | (_, mut x)) = (2, 3);
236    x = 4;
237    f(x);
238}
239"#,
240        );
241
242        check_fix(
243            r#"
244struct Foo(i32);
245
246impl Foo {
247    fn foo(self) {
248        self = Fo$0o(5);
249    }
250}
251"#,
252            r#"
253struct Foo(i32);
254
255impl Foo {
256    fn foo(mut self) {
257        self = Foo(5);
258    }
259}
260"#,
261        );
262    }
263
264    #[test]
265    fn need_mut_fix_not_applicable_on_ref() {
266        check_diagnostics(
267            r#"
268fn main() {
269    let ref x = 2;
270    x = &5;
271  //^^^^^^ error: cannot mutate immutable variable `x`
272}
273"#,
274        );
275        check_diagnostics(
276            r#"
277fn main() {
278    let ref mut x = 2;
279    x = &mut 5;
280  //^^^^^^^^^^ error: cannot mutate immutable variable `x`
281}
282"#,
283        );
284    }
285
286    #[test]
287    fn field_mutate() {
288        check_diagnostics(
289            r#"
290fn f(_: i32) {}
291fn main() {
292    let mut x = (2, 7);
293      //^^^^^ 💡 warn: variable does not need to be mutable
294    f(x.1);
295}
296"#,
297        );
298        check_diagnostics(
299            r#"
300fn f(_: i32) {}
301fn main() {
302    let mut x = (2, 7);
303    x.0 = 5;
304    f(x.1);
305}
306"#,
307        );
308        check_diagnostics(
309            r#"
310fn f(_: i32) {}
311fn main() {
312    let x = (2, 7);
313    x.0 = 5;
314  //^^^^^^^ 💡 error: cannot mutate immutable variable `x`
315    f(x.1);
316}
317"#,
318        );
319    }
320
321    #[test]
322    fn mutable_reference() {
323        check_diagnostics(
324            r#"
325fn main() {
326    let mut x = &mut 2;
327      //^^^^^ 💡 warn: variable does not need to be mutable
328    *x = 5;
329}
330"#,
331        );
332        check_diagnostics(
333            r#"
334fn main() {
335    let x = 2;
336    &mut x;
337  //^^^^^^ 💡 error: cannot mutate immutable variable `x`
338}
339"#,
340        );
341        check_diagnostics(
342            r#"
343fn main() {
344    let x_own = 2;
345    let ref mut x_ref = x_own;
346      //^^^^^^^^^^^^^ 💡 error: cannot mutate immutable variable `x_own`
347    _ = x_ref;
348}
349"#,
350        );
351        check_diagnostics(
352            r#"
353struct Foo;
354impl Foo {
355    fn method(&mut self, _x: i32) {}
356}
357fn main() {
358    let x = Foo;
359    x.method(2);
360  //^ 💡 error: cannot mutate immutable variable `x`
361}
362"#,
363        );
364    }
365
366    #[test]
367    fn regression_14310() {
368        check_diagnostics(
369            r#"
370            //- minicore: copy, builtin_impls
371            fn clone(mut i: &!) -> ! {
372                   //^^^^^ 💡 warn: variable does not need to be mutable
373                *i
374            }
375        "#,
376        );
377    }
378
379    #[test]
380    fn match_closure_capture() {
381        check_diagnostics(
382            r#"
383//- minicore: option
384fn main() {
385    let mut v = &mut Some(2);
386      //^^^^^ 💡 warn: variable does not need to be mutable
387    let _ = || match v {
388        Some(k) => {
389            *k = 5;
390        }
391        None => {}
392    };
393    let v = &mut Some(2);
394    let _ = || match v {
395                   //^ 💡 error: cannot mutate immutable variable `v`
396        ref mut k => {
397            *k = &mut Some(5);
398        }
399    };
400}
401"#,
402        );
403    }
404
405    #[test]
406    fn match_bindings() {
407        check_diagnostics(
408            r#"
409fn main() {
410    match (2, 3) {
411        (x, mut y) => {
412          //^^^^^ 💡 warn: variable does not need to be mutable
413            x = 7;
414          //^^^^^ 💡 error: cannot mutate immutable variable `x`
415            _ = y;
416        }
417    }
418}
419"#,
420        );
421    }
422
423    #[test]
424    fn mutation_in_dead_code() {
425        // This one is interesting. Dead code is not represented at all in the MIR, so
426        // there would be no mutability error for locals in dead code. Rustc tries to
427        // not emit `unused_mut` in this case, but since it works without `mut`, and
428        // special casing it is not trivial, we emit it.
429
430        // Update: now MIR based `unused-variable` is taking over `unused-mut` for the same reason.
431        check_diagnostics(
432            r#"
433fn main() {
434    return;
435    let mut x = 2;
436      //^^^^^ 💡 warn: unused variable
437    &mut x;
438}
439"#,
440        );
441        check_diagnostics(
442            r#"
443fn main() {
444    loop {}
445    let mut x = 2;
446      //^^^^^ 💡 warn: unused variable
447    &mut x;
448}
449"#,
450        );
451        check_diagnostics_with_disabled(
452            r#"
453enum X {}
454fn g() -> X {
455    loop {}
456}
457fn f() -> ! {
458    loop {}
459}
460fn main(b: bool) {
461    if b {
462        f();
463    } else {
464        g();
465    }
466    let mut x = 2;
467      //^^^^^ 💡 warn: unused variable
468    &mut x;
469}
470"#,
471            &["remove-unnecessary-else"],
472        );
473        check_diagnostics_with_disabled(
474            r#"
475fn main(b: bool) {
476    if b {
477        loop {}
478    } else {
479        return;
480    }
481    let mut x = 2;
482      //^^^^^ 💡 warn: unused variable
483    &mut x;
484}
485"#,
486            &["remove-unnecessary-else"],
487        );
488    }
489
490    #[test]
491    fn initialization_is_not_mutation() {
492        check_diagnostics(
493            r#"
494fn f(_: i32) {}
495fn main() {
496    let mut x;
497      //^^^^^ 💡 warn: variable does not need to be mutable
498    x = 5;
499    f(x);
500}
501"#,
502        );
503        check_diagnostics(
504            r#"
505fn f(_: i32) {}
506fn main(b: bool) {
507    let mut x;
508      //^^^^^ 💡 warn: variable does not need to be mutable
509    if b {
510        x = 1;
511    } else {
512        x = 3;
513    }
514    f(x);
515}
516"#,
517        );
518        check_diagnostics(
519            r#"
520fn f(_: i32) {}
521fn main(b: bool) {
522    let x;
523    if b {
524        x = 1;
525    }
526    x = 3;
527  //^^^^^ 💡 error: cannot mutate immutable variable `x`
528    f(x);
529}
530"#,
531        );
532        check_diagnostics(
533            r#"
534fn f(_: i32) {}
535fn main() {
536    let x;
537    loop {
538        x = 1;
539      //^^^^^ 💡 error: cannot mutate immutable variable `x`
540        f(x);
541    }
542}
543"#,
544        );
545        check_diagnostics(
546            r#"
547fn check(_: i32) -> bool {
548    false
549}
550fn main() {
551    loop {
552        let x = 1;
553        if check(x) {
554            break;
555        }
556        let y = (1, 2);
557        if check(y.1) {
558            return;
559        }
560        let z = (1, 2);
561        match z {
562            (k @ 5, ref mut t) if { continue; } => {
563                  //^^^^^^^^^ 💡 error: cannot mutate immutable variable `z`
564                *t = 5;
565                _ = k;
566            }
567            _ => {
568                let y = (1, 2);
569                if check(y.1) {
570                    return;
571                }
572            }
573        }
574    }
575}
576"#,
577        );
578        check_diagnostics(
579            r#"
580fn f(_: i32) {}
581fn main() {
582    loop {
583        let mut x = 1;
584          //^^^^^ 💡 warn: variable does not need to be mutable
585        f(x);
586        if let mut y = 2 {
587             //^^^^^ 💡 warn: variable does not need to be mutable
588            f(y);
589        }
590        match 3 {
591            mut z => f(z),
592          //^^^^^ 💡 warn: variable does not need to be mutable
593        }
594    }
595}
596"#,
597        );
598    }
599
600    #[test]
601    fn initialization_is_not_mutation_in_loop() {
602        check_diagnostics(
603            r#"
604fn main() {
605    let a;
606    loop {
607        let c @ (
608            mut b,
609          //^^^^^ 💡 warn: variable does not need to be mutable
610            mut d
611          //^^^^^ 💡 warn: variable does not need to be mutable
612        );
613        a = 1;
614      //^^^^^ 💡 error: cannot mutate immutable variable `a`
615        b = 1;
616        c = (2, 3);
617        d = 3;
618        _ = (c, b, d);
619    }
620}
621"#,
622        );
623    }
624
625    #[test]
626    fn function_arguments_are_initialized() {
627        check_diagnostics(
628            r#"
629fn f(mut x: i32) {
630   //^^^^^ 💡 warn: variable does not need to be mutable
631   f(x + 2);
632}
633"#,
634        );
635        check_diagnostics(
636            r#"
637fn f(x: i32) {
638   x = 5;
639 //^^^^^ 💡 error: cannot mutate immutable variable `x`
640}
641"#,
642        );
643        check_diagnostics(
644            r#"
645fn f((x, y): (i32, i32)) {
646    let t = [0; 2];
647    x = 5;
648  //^^^^^ 💡 error: cannot mutate immutable variable `x`
649    _ = x;
650    _ = y;
651    _ = t;
652}
653"#,
654        );
655    }
656
657    #[test]
658    fn no_diagnostics_in_case_of_multiple_bounds() {
659        check_diagnostics(
660            r#"
661fn f() {
662    let (b, a, b) = (2, 3, 5);
663    a = 8;
664  //^^^^^ 💡 error: cannot mutate immutable variable `a`
665}
666"#,
667        );
668    }
669
670    #[test]
671    fn for_loop() {
672        check_diagnostics(
673            r#"
674//- minicore: iterators, copy
675fn f(x: [(i32, u8); 10]) {
676    for (a, mut b) in x {
677          //^^^^^ 💡 warn: variable does not need to be mutable
678        a = 2;
679      //^^^^^ 💡 error: cannot mutate immutable variable `a`
680        _ = b;
681    }
682}
683"#,
684        );
685    }
686
687    #[test]
688    fn while_let() {
689        check_diagnostics(
690            r#"
691//- minicore: iterators, copy
692fn f(x: [(i32, u8); 10]) {
693    let mut it = x.into_iter();
694    while let Some((a, mut b)) = it.next() {
695                     //^^^^^ 💡 warn: variable does not need to be mutable
696        while let Some((c, mut d)) = it.next() {
697                         //^^^^^ 💡 warn: variable does not need to be mutable
698            a = 2;
699          //^^^^^ 💡 error: cannot mutate immutable variable `a`
700            c = 2;
701          //^^^^^ 💡 error: cannot mutate immutable variable `c`
702            _ = (b, d);
703        }
704    }
705}
706"#,
707        );
708    }
709
710    #[test]
711    fn index() {
712        check_diagnostics(
713            r#"
714//- minicore: coerce_unsized, index, slice
715fn f() {
716    let x = [1, 2, 3];
717    x[2] = 5;
718  //^^^^^^^^ 💡 error: cannot mutate immutable variable `x`
719    let x = &mut x;
720          //^^^^^^ 💡 error: cannot mutate immutable variable `x`
721    let mut x = x;
722      //^^^^^ 💡 warn: variable does not need to be mutable
723    x[2] = 5;
724}
725"#,
726        );
727    }
728
729    #[test]
730    fn overloaded_index() {
731        check_diagnostics(
732            r#"
733//- minicore: index, copy
734use core::ops::{Index, IndexMut};
735
736struct Foo;
737impl Index<usize> for Foo {
738    type Output = (i32, u8);
739    fn index(&self, _index: usize) -> &(i32, u8) {
740        &(5, 2)
741    }
742}
743impl IndexMut<usize> for Foo {
744    fn index_mut(&mut self, _index: usize) -> &mut (i32, u8) {
745        &mut (5, 2)
746    }
747}
748fn f() {
749    let mut x = Foo;
750      //^^^^^ 💡 warn: variable does not need to be mutable
751    let y = &x[2];
752    _ = (x, y);
753    let x = Foo;
754    let y = &mut x[2];
755               //^💡 error: cannot mutate immutable variable `x`
756    _ = (x, y);
757    let mut x = &mut Foo;
758      //^^^^^ 💡 warn: variable does not need to be mutable
759    let y: &mut (i32, u8) = &mut x[2];
760    _ = (x, y);
761    let x = Foo;
762    let ref mut y = x[7];
763                  //^ 💡 error: cannot mutate immutable variable `x`
764    _ = (x, y);
765    let (ref mut y, _) = x[3];
766                       //^ 💡 error: cannot mutate immutable variable `x`
767    _ = y;
768    match x[10] {
769        //^ 💡 error: cannot mutate immutable variable `x`
770        (ref y, 5) => _ = y,
771        (_, ref mut y) => _ = y,
772    }
773    let mut x = Foo;
774    let mut i = 5;
775      //^^^^^ 💡 warn: variable does not need to be mutable
776    let y = &mut x[i];
777    _ = y;
778}
779"#,
780        );
781    }
782
783    #[test]
784    fn overloaded_deref() {
785        check_diagnostics(
786            r#"
787//- minicore: deref_mut, copy
788use core::ops::{Deref, DerefMut};
789
790struct Foo;
791impl Deref for Foo {
792    type Target = (i32, u8);
793    fn deref(&self) -> &(i32, u8) {
794        &(5, 2)
795    }
796}
797impl DerefMut for Foo {
798    fn deref_mut(&mut self) -> &mut (i32, u8) {
799        &mut (5, 2)
800    }
801}
802fn f() {
803    let mut x = Foo;
804      //^^^^^ 💡 warn: variable does not need to be mutable
805    let y = &*x;
806    _ = (x, y);
807    let x = Foo;
808    let y = &mut *x;
809               // ^ 💡 error: cannot mutate immutable variable `x`
810    _ = (x, y);
811    let x = Foo;
812      //^ 💡 warn: unused variable
813    let x = Foo;
814    let y: &mut (i32, u8) = &mut x;
815                          //^^^^^^ 💡 error: cannot mutate immutable variable `x`
816    _ = (x, y);
817    let ref mut y = *x;
818                  // ^ 💡 error: cannot mutate immutable variable `x`
819    _ = y;
820    let (ref mut y, _) = *x;
821                       // ^ 💡 error: cannot mutate immutable variable `x`
822    _ = y;
823    match *x {
824        // ^ 💡 error: cannot mutate immutable variable `x`
825        (ref y, 5) => _ = y,
826        (_, ref mut y) => _ = y,
827    }
828}
829"#,
830        );
831    }
832
833    #[test]
834    fn or_pattern() {
835        check_diagnostics(
836            r#"
837//- minicore: option
838fn f(_: i32) {}
839fn main() {
840    let ((Some(mut x), None) | (_, Some(mut x))) = (None, Some(7)) else { return };
841             //^^^^^ 💡 warn: variable does not need to be mutable
842
843    f(x);
844}
845"#,
846        );
847        check_diagnostics(
848            r#"
849struct Foo(i32);
850
851const X: Foo = Foo(5);
852const Y: Foo = Foo(12);
853
854const fn f(mut a: Foo) -> bool {
855         //^^^^^ 💡 warn: variable does not need to be mutable
856    match a {
857        X | Y => true,
858        _ => false,
859    }
860}
861"#,
862        );
863    }
864
865    #[test]
866    fn or_pattern_no_terminator() {
867        check_diagnostics(
868            r#"
869enum Foo {
870    A, B, C, D
871}
872
873use Foo::*;
874
875fn f(inp: (Foo, Foo, Foo, Foo)) {
876    let ((A, B, _, x) | (B, C | D, x, _)) = inp else {
877        return;
878    };
879    x = B;
880  //^^^^^ 💡 error: cannot mutate immutable variable `x`
881}
882"#,
883        );
884    }
885
886    #[test]
887    // FIXME: We should have tests for `is_ty_uninhabited_from`
888    fn regression_14421() {
889        check_diagnostics(
890            r#"
891pub enum Tree {
892    Node(TreeNode),
893    Leaf(TreeLeaf),
894}
895
896struct Box<T>(&T);
897
898pub struct TreeNode {
899    pub depth: usize,
900    pub children: [Box<Tree>; 8]
901}
902
903pub struct TreeLeaf {
904    pub depth: usize,
905    pub data: u8
906}
907
908pub fn test() {
909    let mut tree = Tree::Leaf(
910      //^^^^^^^^ 💡 warn: variable does not need to be mutable
911        TreeLeaf {
912            depth: 0,
913            data: 0
914        }
915    );
916    _ = tree;
917}
918"#,
919        );
920    }
921
922    #[test]
923    fn fn_traits() {
924        check_diagnostics(
925            r#"
926//- minicore: fn
927fn fn_ref(mut x: impl Fn(u8) -> u8) -> u8 {
928        //^^^^^ 💡 warn: variable does not need to be mutable
929    x(2)
930}
931fn fn_mut(x: impl FnMut(u8) -> u8) -> u8 {
932    x(2)
933  //^ 💡 error: cannot mutate immutable variable `x`
934}
935fn fn_borrow_mut(mut x: &mut impl FnMut(u8) -> u8) -> u8 {
936               //^^^^^ 💡 warn: variable does not need to be mutable
937    x(2)
938}
939fn fn_once(mut x: impl FnOnce(u8) -> u8) -> u8 {
940         //^^^^^ 💡 warn: variable does not need to be mutable
941    x(2)
942}
943"#,
944        );
945    }
946
947    #[test]
948    fn closure() {
949        check_diagnostics(
950            r#"
951        //- minicore: copy, fn
952        struct X;
953
954        impl X {
955            fn mutate(&mut self) {}
956        }
957
958        fn f() {
959            let x = 5;
960            let closure1 = || { x = 2; };
961                              //^^^^^ 💡 error: cannot mutate immutable variable `x`
962            let _ = closure1();
963                  //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
964            let closure2 = || { x = x; };
965                              //^^^^^ 💡 error: cannot mutate immutable variable `x`
966            let closure3 = || {
967                let x = 2;
968                x = 5;
969              //^^^^^ 💡 error: cannot mutate immutable variable `x`
970                x
971            };
972            let x = X;
973            let closure4 = || { x.mutate(); };
974                              //^ 💡 error: cannot mutate immutable variable `x`
975            _ = (closure2, closure3, closure4);
976        }
977                    "#,
978        );
979        check_diagnostics(
980            r#"
981        //- minicore: copy, fn
982        fn f() {
983            let mut x = 5;
984              //^^^^^ 💡 warn: variable does not need to be mutable
985            let mut y = 2;
986            y = 7;
987            let closure = || {
988                let mut z = 8;
989                z = 3;
990                let mut k = z;
991                  //^^^^^ 💡 warn: variable does not need to be mutable
992                _ = k;
993            };
994            _ = (x, closure);
995        }
996                    "#,
997        );
998        // FIXME: There should be no "unused variable" here, and there should be a mutability error,
999        // but our MIR infra is horribly broken and due to the order in which expressions are lowered
1000        // there is no `StorageLive` for `x` in the closure (in fact, `x` should not even be a variable
1001        // of the closure, the environment should be, but as I said, our MIR infra is horribly broken).
1002        check_diagnostics(
1003            r#"
1004//- minicore: copy, fn
1005fn f() {
1006    let closure = || {
1007        || {
1008            || {
1009                let x = 2;
1010                 // ^ 💡 warn: unused variable
1011                || { || { x = 5; } }
1012            }
1013        }
1014    };
1015    _ = closure;
1016}
1017            "#,
1018        );
1019        check_diagnostics(
1020            r#"
1021//- minicore: copy, fn
1022fn f() {
1023    struct X;
1024    let mut x = X;
1025      //^^^^^ 💡 warn: variable does not need to be mutable
1026    let c1 = || x;
1027    let mut x = X;
1028    let c2 = || { x = X; x };
1029    let mut x = X;
1030    let c3 = move || { x = X; };
1031    _ = (c1, c2, c3);
1032}
1033            "#,
1034        );
1035        check_diagnostics(
1036            r#"
1037        //- minicore: copy, fn, deref_mut
1038        struct X(i32, i64);
1039
1040        fn f() {
1041            let mut x = &mut 5;
1042              //^^^^^ 💡 warn: variable does not need to be mutable
1043            let closure1 = || { *x = 2; };
1044            let _ = closure1();
1045                  //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
1046            let mut x = &mut 5;
1047              //^^^^^ 💡 warn: variable does not need to be mutable
1048            let closure1 = || { *x = 2; &x; };
1049            let _ = closure1();
1050                  //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
1051            let mut x = &mut 5;
1052            let closure1 = || { *x = 2; &x; x = &mut 3; };
1053            let _ = closure1();
1054                  //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
1055            let mut x = &mut 5;
1056              //^^^^^ 💡 warn: variable does not need to be mutable
1057            let closure1 = move || { *x = 2; };
1058            let _ = closure1();
1059                  //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
1060            let mut x = &mut X(1, 2);
1061              //^^^^^ 💡 warn: variable does not need to be mutable
1062            let closure1 = || { x.0 = 2; };
1063            let _ = closure1();
1064                  //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
1065        }
1066                    "#,
1067        );
1068    }
1069
1070    #[test]
1071    fn slice_pattern() {
1072        check_diagnostics(
1073            r#"
1074//- minicore: coerce_unsized, deref_mut, slice, copy
1075fn x(t: &[u8]) {
1076    match t {
1077        &[a, mut b] | &[a, _, mut b] => {
1078           //^^^^^ 💡 warn: variable does not need to be mutable
1079
1080            a = 2;
1081          //^^^^^ 💡 error: cannot mutate immutable variable `a`
1082            _ = b;
1083        }
1084        _ => {}
1085    }
1086}
1087            "#,
1088        );
1089    }
1090
1091    #[test]
1092    fn boxes() {
1093        check_diagnostics(
1094            r#"
1095//- minicore: coerce_unsized, deref_mut, slice
1096use core::ops::{Deref, DerefMut};
1097use core::{marker::Unsize, ops::CoerceUnsized};
1098
1099#[lang = "owned_box"]
1100pub struct Box<T: ?Sized> {
1101    inner: *mut T,
1102}
1103impl<T> Box<T> {
1104    fn new(t: T) -> Self {
1105        #[rustc_box]
1106        Box::new(t)
1107    }
1108}
1109
1110impl<T: ?Sized> Deref for Box<T> {
1111    type Target = T;
1112
1113    fn deref(&self) -> &T {
1114        &**self
1115    }
1116}
1117
1118impl<T: ?Sized> DerefMut for Box<T> {
1119    fn deref_mut(&mut self) -> &mut T {
1120        &mut **self
1121    }
1122}
1123
1124fn f() {
1125    let x = Box::new(5);
1126    x = Box::new(7);
1127  //^^^^^^^^^^^^^^^ 💡 error: cannot mutate immutable variable `x`
1128    let x = Box::new(5);
1129    *x = 7;
1130  //^^^^^^ 💡 error: cannot mutate immutable variable `x`
1131    let mut y = Box::new(5);
1132      //^^^^^ 💡 warn: variable does not need to be mutable
1133    *x = *y;
1134  //^^^^^^^ 💡 error: cannot mutate immutable variable `x`
1135    let x = Box::new(5);
1136    let closure = || *x = 2;
1137                   //^^^^^^ 💡 error: cannot mutate immutable variable `x`
1138    _ = closure;
1139}
1140"#,
1141        );
1142    }
1143
1144    #[test]
1145    fn regression_15143() {
1146        check_diagnostics(
1147            r#"
1148        trait Tr {
1149            type Ty;
1150        }
1151
1152        struct A;
1153
1154        impl Tr for A {
1155            type Ty = (u32, i64);
1156        }
1157
1158        struct B<T: Tr> {
1159            f: <T as Tr>::Ty,
1160        }
1161
1162        fn main(b: B<A>) {
1163            let f = b.f.0;
1164            f = 5;
1165          //^^^^^ 💡 error: cannot mutate immutable variable `f`
1166        }
1167            "#,
1168        );
1169    }
1170
1171    #[test]
1172    fn allow_unused_mut_for_identifiers_starting_with_underline() {
1173        check_diagnostics(
1174            r#"
1175fn f(_: i32) {}
1176fn main() {
1177    let mut _x = 2;
1178    f(_x);
1179}
1180"#,
1181        );
1182    }
1183
1184    #[test]
1185    fn respect_lint_attributes_for_unused_mut() {
1186        check_diagnostics(
1187            r#"
1188fn f(_: i32) {}
1189fn main() {
1190    #[allow(unused_mut)]
1191    let mut x = 2;
1192    f(x);
1193}
1194
1195fn main2() {
1196    #[deny(unused_mut)]
1197    let mut x = 2;
1198      //^^^^^ 💡 error: variable does not need to be mutable
1199    f(x);
1200}
1201"#,
1202        );
1203        check_diagnostics(
1204            r#"
1205macro_rules! mac {
1206    ($($x:expr),*$(,)*) => ({
1207        #[allow(unused_mut)]
1208        let mut vec = 2;
1209        vec
1210    });
1211}
1212
1213fn main2() {
1214    let mut x = mac![];
1215      //^^^^^ 💡 warn: variable does not need to be mutable
1216    _ = x;
1217}
1218        "#,
1219        );
1220    }
1221
1222    #[test]
1223    fn regression_15099() {
1224        check_diagnostics(
1225            r#"
1226//- minicore: iterator, range
1227fn f() {
1228    loop {}
1229    for _ in 0..2 {}
1230}
1231"#,
1232        );
1233    }
1234
1235    #[test]
1236    fn regression_15623() {
1237        check_diagnostics(
1238            r#"
1239//- minicore: fn
1240
1241struct Foo;
1242
1243impl Foo {
1244    fn needs_mut(&mut self) {}
1245}
1246
1247fn foo(mut foo: Foo) {
1248    let mut call_me = || {
1249        let 0 = 1 else { return };
1250        foo.needs_mut();
1251    };
1252    call_me();
1253}
1254"#,
1255        );
1256    }
1257
1258    #[test]
1259    fn regression_15670() {
1260        check_diagnostics(
1261            r#"
1262//- minicore: fn
1263
1264pub struct A {}
1265pub unsafe fn foo(a: *mut A) {
1266    let mut b = || -> *mut A { unsafe { &mut *a } };
1267      //^^^^^ 💡 warn: variable does not need to be mutable
1268    let _ = b();
1269}
1270"#,
1271        );
1272    }
1273
1274    #[test]
1275    fn regression_15799() {
1276        check_diagnostics(
1277            r#"
1278//- minicore: deref_mut
1279struct WrapPtr(*mut u32);
1280
1281impl core::ops::Deref for WrapPtr {
1282    type Target = *mut u32;
1283    fn deref(&self) -> &Self::Target {
1284        &self.0
1285    }
1286}
1287
1288fn main() {
1289    let mut x = 0u32;
1290    let wrap = WrapPtr(&mut x);
1291    unsafe {
1292        **wrap = 6;
1293    }
1294}
1295"#,
1296        );
1297    }
1298
1299    #[test]
1300    fn destructuring_assignment_needs_mut() {
1301        check_diagnostics(
1302            r#"
1303//- minicore: fn
1304
1305fn main() {
1306	let mut var = 1;
1307	let mut func = || (var,) = (2,);
1308	func();
1309}
1310        "#,
1311        );
1312    }
1313
1314    #[test]
1315    fn regression_20662() {
1316        check_diagnostics(
1317            r#"
1318//- minicore: index
1319pub trait A: core::ops::IndexMut<usize> {
1320    type T: A;
1321}
1322
1323fn func(a: &mut impl A, b: &mut [i32]) {
1324    b[0] += 1;
1325}
1326        "#,
1327        );
1328    }
1329}