about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/borrowck/gather_loans.rs2
-rw-r--r--src/librustc/middle/trans/expr.rs10
-rw-r--r--src/librustc/middle/ty.rs5
-rw-r--r--src/librustc/middle/typeck/check/method.rs35
-rw-r--r--src/test/compile-fail/auto-ref-slice-plus-ref.rs18
-rw-r--r--src/test/run-pass/auto-ref-slice-plus-ref.rs48
6 files changed, 111 insertions, 7 deletions
diff --git a/src/librustc/middle/borrowck/gather_loans.rs b/src/librustc/middle/borrowck/gather_loans.rs
index d573bf15d38..a6dd65e4dc7 100644
--- a/src/librustc/middle/borrowck/gather_loans.rs
+++ b/src/librustc/middle/borrowck/gather_loans.rs
@@ -295,7 +295,7 @@ impl gather_loan_ctxt {
                                              autoref.mutbl,
                                              autoref.region)
                     }
-                    ty::AutoBorrowVec => {
+                    ty::AutoBorrowVec | ty::AutoBorrowVecRef => {
                         let cmt_index = mcx.cat_index(expr, cmt);
                         self.guarantee_valid(cmt_index,
                                              autoref.mutbl,
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index e2cb652a537..55f7dfbf956 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -119,7 +119,7 @@ use base::*;
 use syntax::print::pprust::{expr_to_str};
 use util::ppaux::ty_to_str;
 use util::common::indenter;
-use ty::{AutoPtr, AutoBorrowVec, AutoBorrowFn};
+use ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
 use callee::{AutorefArg, DoAutorefArg, DontAutorefArg};
 use middle::ty::MoveValue;
 
@@ -202,6 +202,9 @@ fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
                         AutoBorrowVec => {
                             unpack_datum!(bcx, auto_slice(bcx, datum))
                         }
+                        AutoBorrowVecRef => {
+                            unpack_datum!(bcx, auto_slice_and_ref(bcx, datum))
+                        }
                         AutoBorrowFn => {
                             // currently, all closure types are
                             // represented precisely the same, so no
@@ -243,6 +246,11 @@ fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
         Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
         DatumBlock {bcx: bcx, datum: scratch}
     }
+
+    fn auto_slice_and_ref(bcx: block, datum: Datum) -> DatumBlock {
+        let DatumBlock { bcx, datum } = auto_slice(bcx, datum);
+        auto_ref(bcx, datum)
+    }
 }
 
 fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index e3f2299b9d0..c3500fb309e 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -218,7 +218,7 @@ export DerivedMethodInfo;
 export DerivedFieldInfo;
 export AutoAdjustment;
 export AutoRef;
-export AutoRefKind, AutoPtr, AutoBorrowVec, AutoBorrowFn;
+export AutoRefKind, AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn;
 export iter_bound_traits_and_supertraits;
 export count_traits_and_supertraits;
 
@@ -352,6 +352,9 @@ enum AutoRefKind {
     /// Convert from @[]/~[] to &[] (or str)
     AutoBorrowVec,
 
+    /// Convert from @[]/~[] to &&[] (or str)
+    AutoBorrowVecRef,
+
     /// Convert from @fn()/~fn() to &fn()
     AutoBorrowFn,
 }
diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs
index f1b009c40df..560281765cf 100644
--- a/src/librustc/middle/typeck/check/method.rs
+++ b/src/librustc/middle/typeck/check/method.rs
@@ -707,19 +707,46 @@ impl LookupContext {
             ty_evec(mt, vstore_box) |
             ty_evec(mt, vstore_uniq) |
             ty_evec(mt, vstore_fixed(_)) => {
-                self.search_for_some_kind_of_autorefd_method(
+                // First try to borrow to a slice
+                let entry = self.search_for_some_kind_of_autorefd_method(
                     AutoBorrowVec, autoderefs, [m_const, m_imm, m_mutbl],
                     |m,r| ty::mk_evec(tcx,
                                       {ty:mt.ty, mutbl:m},
-                                      vstore_slice(r)))
+                                      vstore_slice(r)));
+
+                if entry.is_some() { return entry; }
+
+                // Then try to borrow to a slice *and* borrow a pointer.
+                self.search_for_some_kind_of_autorefd_method(
+                    AutoBorrowVecRef, autoderefs, [m_const, m_imm, m_mutbl],
+                    |m,r| {
+                        let slice_ty = ty::mk_evec(tcx,
+                                                   {ty:mt.ty, mutbl:m},
+                                                   vstore_slice(r));
+                        // NB: we do not try to autoref to a mutable
+                        // pointer. That would be creating a pointer
+                        // to a temporary pointer (the borrowed
+                        // slice), so any update the callee makes to
+                        // it can't be observed.
+                        ty::mk_rptr(tcx, r, {ty:slice_ty, mutbl:m_imm})
+                    })
             }
 
             ty_estr(vstore_box) |
             ty_estr(vstore_uniq) |
             ty_estr(vstore_fixed(_)) => {
-                self.search_for_some_kind_of_autorefd_method(
+                let entry = self.search_for_some_kind_of_autorefd_method(
                     AutoBorrowVec, autoderefs, [m_imm],
-                    |_m,r| ty::mk_estr(tcx, vstore_slice(r)))
+                    |_m,r| ty::mk_estr(tcx, vstore_slice(r)));
+
+                if entry.is_some() { return entry; }
+
+                self.search_for_some_kind_of_autorefd_method(
+                    AutoBorrowVecRef, autoderefs, [m_imm],
+                    |m,r| {
+                        let slice_ty = ty::mk_estr(tcx, vstore_slice(r));
+                        ty::mk_rptr(tcx, r, {ty:slice_ty, mutbl:m})
+                    })
             }
 
             ty_trait(*) | ty_fn(*) => {
diff --git a/src/test/compile-fail/auto-ref-slice-plus-ref.rs b/src/test/compile-fail/auto-ref-slice-plus-ref.rs
new file mode 100644
index 00000000000..bd90f9ff0e8
--- /dev/null
+++ b/src/test/compile-fail/auto-ref-slice-plus-ref.rs
@@ -0,0 +1,18 @@
+fn main() {
+
+    // Testing that method lookup does not automatically borrow
+    // vectors to slices then automatically create a &mut self
+    // reference.  That would allow creating a mutable pointer to a
+    // temporary, which would be a source of confusion
+
+    let mut a = @[0];
+    a.test_mut(); //~ ERROR type `@[int]` does not implement any method in scope named `test_mut`
+}
+
+trait MyIter {
+    pure fn test_mut(&mut self);
+}
+
+impl &[int]: MyIter {
+    pure fn test_mut(&mut self) { }
+}
diff --git a/src/test/run-pass/auto-ref-slice-plus-ref.rs b/src/test/run-pass/auto-ref-slice-plus-ref.rs
new file mode 100644
index 00000000000..deb057f7898
--- /dev/null
+++ b/src/test/run-pass/auto-ref-slice-plus-ref.rs
@@ -0,0 +1,48 @@
+// Testing that method lookup automatically both borrows vectors to slices
+// and also references them to create the &self pointer
+
+trait MyIter {
+    pure fn test_imm(&self);
+    pure fn test_const(&const self);
+}
+
+impl &[int]: MyIter {
+    pure fn test_imm(&self) { assert self[0] == 1 }
+    pure fn test_const(&const self) { assert self[0] == 1 }
+}
+
+impl &str: MyIter {
+    pure fn test_imm(&self) { assert *self == "test" }
+    pure fn test_const(&const self) { assert *self == "test" }
+}
+
+fn main() {
+    // NB: Associativity of ~, etc. in this context is surprising. These must be parenthesized
+
+    ([1]).test_imm();
+    (~[1]).test_imm();
+    (@[1]).test_imm();
+    (&[1]).test_imm();
+    ("test").test_imm();
+    (~"test").test_imm();
+    (@"test").test_imm();
+    (&"test").test_imm();
+
+    // XXX: Other types of mutable vecs don't currently exist
+    (@mut [1]).test_imm();
+
+    ([1]).test_const();
+    (~[1]).test_const();
+    (@[1]).test_const();
+    (&[1]).test_const();
+    ("test").test_const();
+    (~"test").test_const();
+    (@"test").test_const();
+    (&"test").test_const();
+
+    (@mut [1]).test_const();
+
+    // NB: We don't do this double autoreffing for &mut self because that would
+    // allow creating a mutable pointer to a temporary, which would be a source
+    // of confusion
+}