Compiler does not find `IndexMut` impl for `Vec`

Retrieving an element from a vector of mutable references works fine calling index_mut() directly

use std::ops::IndexMut;

fn explicit_trait_call(mut a: Vec<&mut i32>) {
    let _i: &mut i32 = *a.index_mut(0);

but fails when using supposedly equivalent indexing syntax:

fn indexing(mut a: Vec<&mut i32>) {
    let _i: &mut i32 = a[0];


The error message is rather surprising:

error[E0596]: cannot borrow data in an index of `std::vec::Vec<&mut i32>` as mutable
 --> src/
4 |     let _i: &mut i32 = a[0];
  |                        ^^^^ cannot borrow as mutable
  = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::vec::Vec<&mut i32>`

It's clearly not true that IndexMut is not implemented for Vec, as evidenced by the first implementation.

This looks like a bug to me, but I couldn't find a corresponding issue on GitHub. Am I missing anything here?

This post was inspired by a question of StackOverflow today.

1 Like

The explicit trait call version only works because the explicit type annotation for _i triggers an implicit reborrow. For what it's worth, I suspect that the logic determining whether to choose Index or IndexMut does not take into account that the implicit reborrow will happen, so it comes to the conclusion that this assignment is a move and wrongly selects Index. This suspicion is purely founded on gut feeling, and not on any knowledge about what the compiler is actually doing.

This compiles, by the way:

fn indexing(mut a: Vec<&mut i32>) {
    let _i: &mut i32 = &mut a[0];

Note that it uses deref coercion to convert the right-hand side from &mut &mut i32 to &mut i32.

The &mut on the right-hand side forces the compiler to select IndexMut, since it's clear that a mutable place expression is required, so this is not surprising. There are many ways to make this work, but I feel the way currently rejected by the compiler should work as well, and is the most natural approach.

At the very least, the error message is wrong and should be fixed.

Thanks for the sanity check, I'll file an issue on GitHub then. :slight_smile:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.