From 2fcf562d163e57acdc4a7e5b0504df2dea6e34e6 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 6 Dec 2012 16:29:17 -0800 Subject: [PATCH] Add an auto-slice-and-ref step to method lookup. Allows ~[T] to work with explicit self --- src/librustc/middle/borrowck/gather_loans.rs | 2 +- src/librustc/middle/trans/expr.rs | 10 +++- src/librustc/middle/ty.rs | 5 +- src/librustc/middle/typeck/check/method.rs | 35 ++++++++++++-- .../compile-fail/auto-ref-slice-plus-ref.rs | 18 +++++++ src/test/run-pass/auto-ref-slice-plus-ref.rs | 48 +++++++++++++++++++ 6 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 src/test/compile-fail/auto-ref-slice-plus-ref.rs create mode 100644 src/test/run-pass/auto-ref-slice-plus-ref.rs 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 +}