]> git.lizzy.rs Git - rust.git/commitdiff
Ignore arguments when looking for `IndexMut` for subsequent `mut` obligation
authorEsteban Küber <esteban@kuber.com.ar>
Sun, 10 May 2020 00:40:04 +0000 (17:40 -0700)
committerEsteban Küber <esteban@kuber.com.ar>
Mon, 11 May 2020 22:45:19 +0000 (15:45 -0700)
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.

src/librustc_typeck/check/method/confirm.rs
src/test/ui/issues/issue-72002.rs [new file with mode: 0644]

index 64dc34ab3b0a7d0bec9a238e60b594a5b74ed2fc..c4805c54a7d43e80b6bad522a345446f4c6f0b5b 100644 (file)
@@ -468,7 +468,9 @@ fn convert_place_derefs_to_mutable(&self) {
 
             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,
diff --git a/src/test/ui/issues/issue-72002.rs b/src/test/ui/issues/issue-72002.rs
new file mode 100644 (file)
index 0000000..54ff893
--- /dev/null
@@ -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
+}