Skip to content

Commit 0dcde02

Browse files
committed
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.
1 parent 4802f09 commit 0dcde02

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

src/librustc_typeck/check/method/confirm.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,9 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
468468

469469
match expr.kind {
470470
hir::ExprKind::Index(ref base_expr, ref index_expr) => {
471-
let index_expr_ty = self.node_ty(index_expr.hir_id);
471+
// We need to get the final type in case dereferences were needed for the trait
472+
// to apply (#72002).
473+
let index_expr_ty = self.tables.borrow().expr_ty_adjusted(index_expr);
472474
self.convert_place_op_to_mutable(
473475
PlaceOp::Index,
474476
expr,

src/test/ui/issues/issue-72002.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// check-pass
2+
struct Indexable;
3+
4+
impl Indexable {
5+
fn boo(&mut self) {}
6+
}
7+
8+
impl std::ops::Index<&str> for Indexable {
9+
type Output = Indexable;
10+
11+
fn index(&self, field: &str) -> &Indexable {
12+
self
13+
}
14+
}
15+
16+
impl std::ops::IndexMut<&str> for Indexable {
17+
fn index_mut(&mut self, field: &str) -> &mut Indexable {
18+
self
19+
}
20+
}
21+
22+
fn main() {
23+
let mut v = Indexable;
24+
let field = "hello".to_string();
25+
26+
v[field.as_str()].boo();
27+
28+
v[&field].boo(); // < This should work
29+
}

0 commit comments

Comments
 (0)