for (i, &expr) in exprs.iter().rev().enumerate() {
debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?}", i, expr);
- // Fix up the adjustment.
- let autoderefs = match self.tables.borrow_mut().adjustments.get_mut(&expr.id) {
- Some(&mut Adjustment {
- kind: Adjust::DerefRef { autoderefs, ref mut autoref, .. }, ref mut target
- }) => {
- if let &mut Some(AutoBorrow::Ref(_, ref mut mutbl)) = autoref {
- *mutbl = hir::Mutability::MutMutable;
- *target = match target.sty {
- ty::TyRef(r, ty::TypeAndMut { ty, .. }) =>
- self.tcx.mk_ref(r, ty::TypeAndMut { ty, mutbl: *mutbl }),
- _ => span_bug!(expr.span, "AutoBorrow::Ref resulted in non-ref {:?}",
- target)
- };
- }
- autoderefs
- }
+ // Fix up the autoderefs. Autorefs can only occur immediately preceding
+ // overloaded lvalue ops, and will be fixed by them in order to get
+ // the correct region.
+ let autoderefs = match self.tables.borrow().adjustments.get(&expr.id) {
+ Some(&Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) => autoderefs,
Some(_) | None => 0
};
let method = self.try_overloaded_lvalue_op(
expr.span, None, base_ty, arg_tys, PreferMutLvalue, op);
- let ok = method.expect("re-trying op failed");
+ let ok = match method {
+ Some(method) => method,
+ None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed")
+ };
let method = self.register_infer_ok_obligations(ok);
debug!("convert_lvalue_op_to_mutable: method={:?}", method);
self.tables.borrow_mut().method_map.insert(method_call, method);
+
+ // Convert the autoref in the base expr to mutable with the correct
+ // region and mutability.
+ if let Some(&mut Adjustment {
+ ref mut target, kind: Adjust::DerefRef {
+ autoref: Some(AutoBorrow::Ref(ref mut r, ref mut mutbl)), ..
+ }
+ }) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) {
+ debug!("convert_lvalue_op_to_mutable: converting autoref of {:?}", target);
+
+ // extract method return type, which will be &mut T;
+ // all LB regions should have been instantiated during method lookup
+ let method_sig = self.tcx.no_late_bound_regions(&method.ty.fn_sig()).unwrap();
+
+ *target = method_sig.inputs()[0];
+ if let ty::TyRef(r_, mt) = target.sty {
+ *r = r_;
+ *mutbl = mt.mutbl;
+ } else {
+ span_bug!(expr.span, "input to lvalue op is not a ref?");
+ }
+ }
}
///////////////////////////////////////////////////////////////////////////
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::collections::HashMap;
+fn main() {
+ let things: HashMap<String, Vec<String>> = HashMap::new();
+ for src in things.keys() {
+ things[src.as_str()].sort(); //~ ERROR cannot borrow immutable
+ }
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ops::{Index, IndexMut};
+
+struct S;
+struct H;
+
+impl S {
+ fn f(&mut self) {}
+}
+
+impl Index<u32> for H {
+ type Output = S;
+ fn index(&self, index: u32) -> &S {
+ unimplemented!()
+ }
+}
+
+impl IndexMut<u32> for H {
+ fn index_mut(&mut self, index: u32) -> &mut S {
+ unimplemented!()
+ }
+}
+
+fn main() {
+ H["?"].f(); //~ ERROR mismatched types
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// check that we link regions in mutable lvalue ops correctly - issue #41774
+
+struct Data(i32);
+
+trait OhNo {
+ fn oh_no(&mut self, other: &Vec<Data>) { loop {} }
+}
+
+impl OhNo for Data {}
+impl OhNo for [Data] {}
+
+fn main() {
+ let mut v = vec![Data(0)];
+ v[0].oh_no(&v); //~ ERROR cannot borrow `v` as immutable because
+ (*v).oh_no(&v); //~ ERROR cannot borrow `v` as immutable because
+}