fn main() {
let mut s: (i32, i32);
s.0 = 3;
s.1 = 4;
println!("{} {}", s.0, s.1);
}
Causes the following warning:
warning: variable does not need to be mutable
--> src/main.rs:2:9
|
2 | let mut s: (i32, i32);
| ----^
| |
| help: remove this `mut`
|
= note: #[warn(unused_mut)] on by default
Removing mut causes an error:
error[E0594]: cannot assign to `s.0`, as `s` is not declared as mutable
--> src/main.rs:3:5
|
2 | let s: (i32, i32);
| - help: consider changing this to be mutable: `mut s`
3 | s.0 = 3;
| ^^^^^^^ cannot assign
error[E0594]: cannot assign to `s.1`, as `s` is not declared as mutable
--> src/main.rs:4:5
|
2 | let s: (i32, i32);
| - help: consider changing this to be mutable: `mut s`
3 | s.0 = 3;
4 | s.1 = 4;
| ^^^^^^^ cannot assign
error: aborting due to 2 previous errors
Tested on nightly on the playground. This code is stupid, but I don't think it should report "unused mut" warnings.
I think the error (that partial initialization requires mut) is wrong, or at least surprising.
cc @nikomatsakis @pnkfelix
So, we decided to echo existing borrowck behavior here, which does require a mut for.. no particularly good reason (this is https://github.com/rust-lang/rust/issues/21232, a long-standing issue). I did this as a performance optimization in https://github.com/rust-lang/rust/pull/53258 with the intention that we would expand the handling of immutable variables at some later point.
The simplest thing would be to update the "mut checker" to understand this limitation, I suppose. The more complex thing would be to try and fix #21232 — this feels like something we might consider, as NLL is reaching a decent point.
In terms of how to suppress the false warning, here are a few tips:
The BorrowCheckContext has a field used_muts indicating the variables and things where a mut declaration was *required::
So we probably need to add something to that set when we see a.b = c. That is a MIR assignment, so it winds up invoking mutate_place:
Here we special case out assignments to immutable local variables (not this case):
and then fall through to access_place:
Something in there must be failing to update used_muts...
@xfix out of curiosity, how did you notice this bug? Are you relying on the current behavior of being able to assign to (but not read from) a field of an uninitialized variable?
@nikomatsakis I just like abusing compiler edge cases hoping to find bugs, this isn't from an actual program.
Most helpful comment
@nikomatsakis I just like abusing compiler edge cases hoping to find bugs, this isn't from an actual program.