about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2017-05-08 17:05:03 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2017-05-08 17:05:03 +0300
commit052d071bb28048c0e1d481891a6017ca97e326e7 (patch)
tree7f23da00afb9a07bc149c07cb7b9e294254eb6b2 /src
parentced823e267c132fab172b1890b24073995e79ffa (diff)
downloadrust-052d071bb28048c0e1d481891a6017ca97e326e7.tar.gz
rust-052d071bb28048c0e1d481891a6017ca97e326e7.zip
try to fix lvalue ops for real
Hopefully this is the last PR needed.

Fixes #41726.
Fixes #41742.
Fixes #41774.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_typeck/check/method/confirm.rs48
-rw-r--r--src/test/compile-fail/issue-41726.rs17
-rw-r--r--src/test/compile-fail/issue-41742.rs35
-rw-r--r--src/test/compile-fail/regions-adjusted-lvalue-op.rs26
4 files changed, 109 insertions, 17 deletions
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index aad14bc975d..5cec71a7eb7 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -433,22 +433,11 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         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
             };
 
@@ -502,10 +491,35 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
 
         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?");
+            }
+        }
     }
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/src/test/compile-fail/issue-41726.rs b/src/test/compile-fail/issue-41726.rs
new file mode 100644
index 00000000000..c8cd9209bce
--- /dev/null
+++ b/src/test/compile-fail/issue-41726.rs
@@ -0,0 +1,17 @@
+// 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
+    }
+}
diff --git a/src/test/compile-fail/issue-41742.rs b/src/test/compile-fail/issue-41742.rs
new file mode 100644
index 00000000000..067531e036a
--- /dev/null
+++ b/src/test/compile-fail/issue-41742.rs
@@ -0,0 +1,35 @@
+// 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
+}
diff --git a/src/test/compile-fail/regions-adjusted-lvalue-op.rs b/src/test/compile-fail/regions-adjusted-lvalue-op.rs
new file mode 100644
index 00000000000..167c8630707
--- /dev/null
+++ b/src/test/compile-fail/regions-adjusted-lvalue-op.rs
@@ -0,0 +1,26 @@
+// 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
+}