From 0dcde02cc7bdd47f48af12e911829390c2864c47 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Esteban=20K=C3=BCber?= Date: Sat, 9 May 2020 17:40:04 -0700 Subject: [PATCH 1/1] Ignore arguments when looking for `IndexMut` for subsequent `mut` obligation 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 | 4 ++- src/test/ui/issues/issue-72002.rs | 29 +++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/issues/issue-72002.rs diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 64dc34ab3b0..c4805c54a7d 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -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 index 00000000000..54ff89355ff --- /dev/null +++ b/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 +} -- 2.44.0