Skip to content

Commit

Permalink
Ignore arguments when looking for IndexMut for subsequent mut obl…
Browse files Browse the repository at this point in the history
…igation

Given code like `v[&field].boo();` where `field: String` and
`.boo(&mut self)`, typeck will have decided that `v` is accessed using
`Index`, but when `boo` adds a new `mut` obligation,
`convert_place_op_to_mutable` is called. When this happens, for *some
reason* the arguments' dereference adjustments are completely ignored
causing an error saying that `IndexMut` is not satisfied:

```
error[E0596]: cannot borrow data in an index of `Indexable` as mutable
  --> src/main.rs:30:5
   |
30 |     v[&field].boo();
   |     ^^^^^^^^^ cannot borrow as mutable
   |
   = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `Indexable`
```

This is not true, but by changing `try_overloaded_place_op` to retry
when given `Needs::MutPlace` without passing the argument types, the
example successfully compiles.

I believe there might be more appropriate ways to deal with this.
  • Loading branch information
estebank committed May 11, 2020
1 parent 4802f09 commit 0dcde02
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 1 deletion.
4 changes: 3 additions & 1 deletion src/librustc_typeck/check/method/confirm.rs
Expand Up @@ -468,7 +468,9 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {

match expr.kind {
hir::ExprKind::Index(ref base_expr, ref index_expr) => {
let index_expr_ty = self.node_ty(index_expr.hir_id);
// We need to get the final type in case dereferences were needed for the trait
// to apply (#72002).
let index_expr_ty = self.tables.borrow().expr_ty_adjusted(index_expr);
self.convert_place_op_to_mutable(
PlaceOp::Index,
expr,
Expand Down
29 changes: 29 additions & 0 deletions src/test/ui/issues/issue-72002.rs
@@ -0,0 +1,29 @@
// check-pass
struct Indexable;

impl Indexable {
fn boo(&mut self) {}
}

impl std::ops::Index<&str> for Indexable {
type Output = Indexable;

fn index(&self, field: &str) -> &Indexable {
self
}
}

impl std::ops::IndexMut<&str> for Indexable {
fn index_mut(&mut self, field: &str) -> &mut Indexable {
self
}
}

fn main() {
let mut v = Indexable;
let field = "hello".to_string();

v[field.as_str()].boo();

v[&field].boo(); // < This should work
}

0 comments on commit 0dcde02

Please sign in to comment.