about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-12-12 13:21:58 +0000
committerbors <bors@rust-lang.org>2014-12-12 13:21:58 +0000
commit2ea38750e92e199654968aa4dbb3462de71f7b50 (patch)
tree878188cc3b519728eace80d24763ca14a11e577a
parentd2e2bd1b442948d4754bb1eb09ff1914a83604dd (diff)
parent061a87e5194cde49b5501323ff5ca7ca5a172441 (diff)
downloadrust-2ea38750e92e199654968aa4dbb3462de71f7b50.tar.gz
rust-2ea38750e92e199654968aa4dbb3462de71f7b50.zip
auto merge of #19617 : nikomatsakis/rust/issue-19261-2, r=nrc
**First commit.** Patch up debruijn indices. Fixes #19537. 

**Second commit.** Stop reborrowing so much. Fixes #19147. Fixes #19261.

r? @nick29581 
-rw-r--r--src/librustc_trans/trans/datum.rs8
-rw-r--r--src/librustc_typeck/astconv.rs17
-rw-r--r--src/librustc_typeck/check/method/mod.rs1
-rw-r--r--src/librustc_typeck/check/method/probe.rs39
-rw-r--r--src/librustc_typeck/collect.rs20
-rw-r--r--src/test/compile-fail/borrowck-return-variable-on-stack-via-clone.rs20
-rw-r--r--src/test/compile-fail/hrtb-debruijn-in-receiver.rs28
-rw-r--r--src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs54
8 files changed, 164 insertions, 23 deletions
diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs
index 23a261842b2..edcc8edaf7f 100644
--- a/src/librustc_trans/trans/datum.rs
+++ b/src/librustc_trans/trans/datum.rs
@@ -535,10 +535,10 @@ impl<'tcx, K: KindOps + fmt::Show> Datum<'tcx, K> {
     /// Copies the value into a new location. This function always preserves the existing datum as
     /// a valid value. Therefore, it does not consume `self` and, also, cannot be applied to affine
     /// values (since they must never be duplicated).
-    pub fn shallow_copy<'blk, 'tcx>(&self,
-                                    bcx: Block<'blk, 'tcx>,
-                                    dst: ValueRef)
-                                    -> Block<'blk, 'tcx> {
+    pub fn shallow_copy<'blk>(&self,
+                              bcx: Block<'blk, 'tcx>,
+                              dst: ValueRef)
+                              -> Block<'blk, 'tcx> {
         /*!
          * Copies the value into a new location. This function always
          * preserves the existing datum as a valid value. Therefore,
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 7f1aad8ca77..790d882f836 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -54,6 +54,7 @@ use middle::resolve_lifetime as rl;
 use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs};
 use middle::subst::{VecPerParamSpace};
 use middle::ty::{mod, Ty};
+use middle::ty_fold;
 use rscope::{mod, UnelidableRscope, RegionScope, SpecificRscope,
              ShiftedRscope, BindingRscope};
 use TypeAndSubsts;
@@ -1062,7 +1063,8 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>(
                            opt_self_info: Option<SelfInfo<'a, 'tcx>>,
                            decl: &ast::FnDecl)
                            -> (ty::BareFnTy<'tcx>,
-                               Option<ty::ExplicitSelfCategory>) {
+                               Option<ty::ExplicitSelfCategory>)
+{
     debug!("ty_of_method_or_bare_fn");
 
     // New region names that appear inside of the arguments of the function
@@ -1078,6 +1080,11 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>(
     let (self_ty, mut implied_output_region) = match opt_self_info {
         None => (None, None),
         Some(self_info) => {
+            // Shift regions in the self type by 1 to account for the binding
+            // level introduced by the function itself.
+            let untransformed_self_ty =
+                ty_fold::shift_regions(this.tcx(), 1, &self_info.untransformed_self_ty);
+
             // Figure out and record the explicit self category.
             let explicit_self_category =
                 determine_explicit_self_category(this, &rb, &self_info);
@@ -1087,21 +1094,19 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>(
                     (None, None)
                 }
                 ty::ByValueExplicitSelfCategory => {
-                    (Some(self_info.untransformed_self_ty), None)
+                    (Some(untransformed_self_ty), None)
                 }
                 ty::ByReferenceExplicitSelfCategory(region, mutability) => {
                     (Some(ty::mk_rptr(this.tcx(),
                                       region,
                                       ty::mt {
-                                        ty: self_info.untransformed_self_ty,
+                                        ty: untransformed_self_ty,
                                         mutbl: mutability
                                       })),
                      Some(region))
                 }
                 ty::ByBoxExplicitSelfCategory => {
-                    (Some(ty::mk_uniq(this.tcx(),
-                                      self_info.untransformed_self_ty)),
-                     None)
+                    (Some(ty::mk_uniq(this.tcx(), untransformed_self_ty)), None)
                 }
             }
         }
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index b6c9d8b2d21..53bda93b28e 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -100,6 +100,7 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
            call_expr.repr(fcx.tcx()),
            self_expr.repr(fcx.tcx()));
 
+    let self_ty = fcx.infcx().resolve_type_vars_if_possible(self_ty);
     let pick = try!(probe::probe(fcx, span, method_name, self_ty, call_expr.id));
     Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types))
 }
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 6ff276edbce..18ab4f79b0b 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -168,7 +168,7 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         check::autoderef(
             fcx, span, self_ty, None, NoPreference,
             |t, d| {
-                let adjustment = consider_reborrow(t, d);
+                let adjustment = AutoDeref(d);
                 steps.push(CandidateStep { self_ty: t, adjustment: adjustment });
                 None::<()> // keep iterating until we can't anymore
             });
@@ -185,14 +185,6 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     }
 
     return steps;
-
-    fn consider_reborrow(ty: Ty, d: uint) -> PickAdjustment {
-        // Insert a `&*` or `&mut *` if this is a reference type:
-        match ty.sty {
-            ty::ty_rptr(_, ref mt) => AutoRef(mt.mutbl, box AutoDeref(d+1)),
-            _ => AutoDeref(d),
-        }
-    }
 }
 
 impl<'a,'tcx> ProbeContext<'a,'tcx> {
@@ -626,7 +618,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             return None;
         }
 
-        match self.pick_adjusted_method(step) {
+        match self.pick_by_value_method(step) {
             Some(result) => return Some(result),
             None => {}
         }
@@ -644,11 +636,34 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
         }
     }
 
-    fn pick_adjusted_method(&mut self,
+    fn pick_by_value_method(&mut self,
                             step: &CandidateStep<'tcx>)
                             -> Option<PickResult<'tcx>>
     {
-        self.pick_method(step.self_ty).map(|r| self.adjust(r, step.adjustment.clone()))
+        /*!
+         * For each type `T` in the step list, this attempts to find a
+         * method where the (transformed) self type is exactly `T`. We
+         * do however do one transformation on the adjustment: if we
+         * are passing a region pointer in, we will potentially
+         * *reborrow* it to a shorter lifetime. This allows us to
+         * transparently pass `&mut` pointers, in particular, without
+         * consuming them for their entire lifetime.
+         */
+
+        let adjustment = match step.adjustment {
+            AutoDeref(d) => consider_reborrow(step.self_ty, d),
+            AutoUnsizeLength(..) | AutoRef(..) => step.adjustment.clone(),
+        };
+
+        return self.pick_method(step.self_ty).map(|r| self.adjust(r, adjustment.clone()));
+
+        fn consider_reborrow(ty: Ty, d: uint) -> PickAdjustment {
+            // Insert a `&*` or `&mut *` if this is a reference type:
+            match ty.sty {
+                ty::ty_rptr(_, ref mt) => AutoRef(mt.mutbl, box AutoDeref(d+1)),
+                _ => AutoDeref(d),
+            }
+        }
     }
 
     fn pick_autorefd_method(&mut self,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 74ac9c480de..4ad6dc292a7 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1055,7 +1055,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
                       ref selfty,
                       ref impl_items) => {
             // Create generics from the generics specified in the impl head.
-            let ty_generics = ty_generics_for_type(
+            let ty_generics = ty_generics_for_impl(
                     ccx,
                     generics,
                     CreateTypeParametersForAssociatedTypes);
@@ -1655,6 +1655,24 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     generics
 }
 
+fn ty_generics_for_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                  generics: &ast::Generics,
+                                  create_type_parameters_for_associated_types:
+                                      CreateTypeParametersForAssociatedTypesFlag)
+                                  -> ty::Generics<'tcx>
+{
+    let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics);
+    debug!("ty_generics_for_impl: early_lifetimes={}",
+           early_lifetimes);
+    ty_generics(ccx,
+                subst::TypeSpace,
+                early_lifetimes.as_slice(),
+                generics.ty_params.as_slice(),
+                ty::Generics::empty(),
+                &generics.where_clause,
+                create_type_parameters_for_associated_types)
+}
+
 fn ty_generics_for_fn_or_method<'tcx,AC>(
         this: &AC,
         generics: &ast::Generics,
diff --git a/src/test/compile-fail/borrowck-return-variable-on-stack-via-clone.rs b/src/test/compile-fail/borrowck-return-variable-on-stack-via-clone.rs
new file mode 100644
index 00000000000..7529943f0bc
--- /dev/null
+++ b/src/test/compile-fail/borrowck-return-variable-on-stack-via-clone.rs
@@ -0,0 +1,20 @@
+// Copyright 2014 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 when we clone a `&T` pointer we properly relate the
+// lifetime of the pointer which results to the pointer being cloned.
+// Bugs in method resolution have sometimes broken this connection.
+// Issue #19261.
+
+fn leak<'a, T>(x: T) -> &'a T {
+    (&x).clone() //~ ERROR `x` does not live long enough
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/hrtb-debruijn-in-receiver.rs b/src/test/compile-fail/hrtb-debruijn-in-receiver.rs
new file mode 100644
index 00000000000..2dbd16107b0
--- /dev/null
+++ b/src/test/compile-fail/hrtb-debruijn-in-receiver.rs
@@ -0,0 +1,28 @@
+// Copyright 2014 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.
+
+// Test the case where the `Self` type has a bound lifetime that must
+// be adjusted in the fn signature. Issue #19537.
+
+use std::collections::HashMap;
+
+struct Foo<'a> {
+    map: HashMap<uint, &'a str>
+}
+
+impl<'a> Foo<'a> {
+    fn new() -> Foo<'a> { panic!() }
+    fn insert(&'a mut self) { }
+}
+fn main() {
+    let mut foo = Foo::new();
+    foo.insert();
+    foo.insert(); //~ ERROR cannot borrow
+}
diff --git a/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs b/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs
new file mode 100644
index 00000000000..00319d57f8d
--- /dev/null
+++ b/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs
@@ -0,0 +1,54 @@
+// Copyright 2014 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.
+
+// Test that an `&mut self` method, when invoked on an lvalue whose
+// type is `&mut [u8]`, passes in a pointer to the lvalue and not a
+// temporary. Issue #19147.
+
+use std::raw;
+use std::mem;
+use std::slice;
+use std::io::IoResult;
+
+trait MyWriter {
+    fn my_write(&mut self, buf: &[u8]) -> IoResult<()>;
+}
+
+impl<'a> MyWriter for &'a mut [u8] {
+    fn my_write(&mut self, buf: &[u8]) -> IoResult<()> {
+        slice::bytes::copy_memory(*self, buf);
+
+        let write_len = buf.len();
+        unsafe {
+            *self = mem::transmute(raw::Slice {
+                data: self.as_ptr().offset(write_len as int),
+                len: self.len() - write_len,
+            });
+        }
+
+        Ok(())
+    }
+}
+
+fn main() {
+    let mut buf = [0_u8, .. 6];
+
+    {
+        let mut writer = buf.as_mut_slice();
+        writer.my_write(&[0, 1, 2]).unwrap();
+        writer.my_write(&[3, 4, 5]).unwrap();
+    }
+
+    // If `my_write` is not modifying `buf` in place, then we will
+    // wind up with `[3, 4, 5, 0, 0, 0]` because the first call to
+    // `my_write()` doesn't update the starting point for the write.
+
+    assert_eq!(buf, [0, 1, 2, 3, 4, 5]);
+}