about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-09-17 08:49:39 -0700
committerAlex Crichton <alex@alexcrichton.com>2014-09-17 08:49:39 -0700
commit2278f9575d29e76fb9d4df551b2dfc7489140c5c (patch)
tree9336ca149617ccf01ffa59c1bc23299c0f8a0595
parentdf34b082abb184054961a641bbe40a450ec92b0d (diff)
parente86c87a81e69de51cfed5719888840f25266a8d8 (diff)
downloadrust-2278f9575d29e76fb9d4df551b2dfc7489140c5c.tar.gz
rust-2278f9575d29e76fb9d4df551b2dfc7489140c5c.zip
rollup merge of #17310 : nikomatsakis/type-bounds-generalize-to-multiple-object-bounds
-rw-r--r--src/librustc/metadata/tydecode.rs4
-rw-r--r--src/librustc/metadata/tyencode.rs2
-rw-r--r--src/librustc/middle/ty.rs7
-rw-r--r--src/librustc/middle/ty_fold.rs2
-rw-r--r--src/librustc/middle/typeck/check/mod.rs2
-rw-r--r--src/librustc/middle/typeck/check/regionck.rs2
-rw-r--r--src/librustc/middle/typeck/check/regionmanip.rs2
-rw-r--r--src/librustc/middle/typeck/collect.rs12
-rw-r--r--src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs4
-rw-r--r--src/test/compile-fail/regions-close-over-type-parameter-multiple.rs32
-rw-r--r--src/test/run-pass/regions-close-over-type-parameter-successfully.rs30
11 files changed, 81 insertions, 18 deletions
diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index 53203663bb1..0e888b39b85 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -680,14 +680,14 @@ fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds {
     let builtin_bounds = parse_builtin_bounds(st, |x,y| conv(x,y));
 
     let mut param_bounds = ty::ParamBounds {
-        opt_region_bound: None,
+        region_bounds: Vec::new(),
         builtin_bounds: builtin_bounds,
         trait_bounds: Vec::new()
     };
     loop {
         match next(st) {
             'R' => {
-                param_bounds.opt_region_bound = Some(parse_region(st, |x, y| conv (x, y)));
+                param_bounds.region_bounds.push(parse_region(st, |x, y| conv (x, y)));
             }
             'I' => {
                 param_bounds.trait_bounds.push(Rc::new(parse_trait_ref(st, |x,y| conv(x,y))));
diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs
index cbf558b6b48..3ef1d15cf56 100644
--- a/src/librustc/metadata/tyencode.rs
+++ b/src/librustc/metadata/tyencode.rs
@@ -366,7 +366,7 @@ pub fn enc_existential_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::Exi
 pub fn enc_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ParamBounds) {
     enc_builtin_bounds(w, cx, &bs.builtin_bounds);
 
-    for &r in bs.opt_region_bound.iter() {
+    for &r in bs.region_bounds.iter() {
         mywrite!(w, "R");
         enc_region(w, cx, r);
     }
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 535294a70a0..09912b54583 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -1008,7 +1008,7 @@ pub enum type_err {
 /// as well as the existential type parameter in an object type.
 #[deriving(PartialEq, Eq, Hash, Clone, Show)]
 pub struct ParamBounds {
-    pub opt_region_bound: Option<ty::Region>,
+    pub region_bounds: Vec<ty::Region>,
     pub builtin_bounds: BuiltinBounds,
     pub trait_bounds: Vec<Rc<TraitRef>>
 }
@@ -1016,7 +1016,8 @@ pub struct ParamBounds {
 /// Bounds suitable for an existentially quantified type parameter
 /// such as those that appear in object types or closure types. The
 /// major difference between this case and `ParamBounds` is that
-/// general purpose trait bounds are omitted.
+/// general purpose trait bounds are omitted and there must be
+/// *exactly one* region.
 #[deriving(PartialEq, Eq, Hash, Clone, Show)]
 pub struct ExistentialBounds {
     pub region_bound: ty::Region,
@@ -4865,7 +4866,7 @@ pub fn required_region_bounds(tcx: &ctxt,
         trait_bounds,
         |trait_ref| {
             let bounds = ty::bounds_for_trait_ref(tcx, &*trait_ref);
-            push_region_bounds(bounds.opt_region_bound.as_slice(),
+            push_region_bounds(bounds.region_bounds.as_slice(),
                                bounds.builtin_bounds,
                                &mut all_bounds);
             debug!("from {}: bounds={} all_bounds={}",
diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs
index 549f0daef81..48fa6f823b0 100644
--- a/src/librustc/middle/ty_fold.rs
+++ b/src/librustc/middle/ty_fold.rs
@@ -287,7 +287,7 @@ impl TypeFoldable for ty::ExistentialBounds {
 impl TypeFoldable for ty::ParamBounds {
     fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ParamBounds {
         ty::ParamBounds {
-            opt_region_bound: self.opt_region_bound.fold_with(folder),
+            region_bounds: self.region_bounds.fold_with(folder),
             builtin_bounds: self.builtin_bounds.fold_with(folder),
             trait_bounds: self.trait_bounds.fold_with(folder),
         }
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 0af20cf2bcc..2f5b6e1fa03 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -2005,7 +2005,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let region_bounds =
             ty::required_region_bounds(
                 self.tcx(),
-                param_bound.opt_region_bound.as_slice(),
+                param_bound.region_bounds.as_slice(),
                 param_bound.builtin_bounds,
                 param_bound.trait_bounds.as_slice());
         for &r in region_bounds.iter() {
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index 37b77e872ca..a8f2a8f6f1d 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -1880,7 +1880,7 @@ fn param_must_outlive(rcx: &Rcx,
     let param_bound = param_env.bounds.get(param_ty.space, param_ty.idx);
     param_bounds =
         ty::required_region_bounds(rcx.tcx(),
-                                   param_bound.opt_region_bound.as_slice(),
+                                   param_bound.region_bounds.as_slice(),
                                    param_bound.builtin_bounds,
                                    param_bound.trait_bounds.as_slice());
 
diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs
index 60e502786ab..8bcbe4b7929 100644
--- a/src/librustc/middle/typeck/check/regionmanip.rs
+++ b/src/librustc/middle/typeck/check/regionmanip.rs
@@ -327,7 +327,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
 
                 // Inspect bounds on this type parameter for any
                 // region bounds.
-                for &r in type_param_def.bounds.opt_region_bound.iter() {
+                for &r in type_param_def.bounds.region_bounds.iter() {
                     self.stack.push((r, Some(ty)));
                     self.accumulate_from_ty(type_param_ty);
                     self.stack.pop().unwrap();
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index c7b4a78492b..dedb860967c 100644
--- a/src/librustc/middle/typeck/collect.rs
+++ b/src/librustc/middle/typeck/collect.rs
@@ -1044,7 +1044,7 @@ fn ty_generics_for_trait(ccx: &CrateCtxt,
         ident: special_idents::type_self,
         def_id: local_def(param_id),
         bounds: ty::ParamBounds {
-            opt_region_bound: None,
+            region_bounds: vec!(),
             builtin_bounds: ty::empty_builtin_bounds(),
             trait_bounds: vec!(self_trait_ref),
         },
@@ -1280,12 +1280,12 @@ fn conv_param_bounds(ccx: &CrateCtxt,
         .map(|b| instantiate_trait_ref(ccx, b, param_ty.to_ty(ccx.tcx)))
         .chain(unboxed_fn_ty_bounds)
         .collect();
-    let opt_region_bound =
-        astconv::compute_opt_region_bound(
-            ccx.tcx, span, builtin_bounds, region_bounds.as_slice(),
-            trait_bounds.as_slice());
+    let region_bounds: Vec<ty::Region> =
+        region_bounds.move_iter()
+        .map(|r| ast_region_to_region(ccx.tcx, r))
+        .collect();
     ty::ParamBounds {
-        opt_region_bound: opt_region_bound,
+        region_bounds: region_bounds,
         builtin_bounds: builtin_bounds,
         trait_bounds: trait_bounds,
     }
diff --git a/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs
index 40cff3e466b..6b3c92e0028 100644
--- a/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs
+++ b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs
@@ -35,10 +35,10 @@ fn test<
     'a,
     'b,
     A:IsStatic,
-    B:Is<'a>+Is2<'b>,    //~ ERROR ambiguous lifetime bound
+    B:Is<'a>+Is2<'b>, // OK in a parameter, but not an object type.
     C:'b+Is<'a>+Is2<'b>,
     D:Is<'a>+Is2<'static>,
-    E:'a+'b //~ ERROR only a single explicit lifetime bound is permitted
+    E:'a+'b           // OK in a parameter, but not an object type.
 >() { }
 
 fn main() { }
diff --git a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs
new file mode 100644
index 00000000000..cec785c6e96
--- /dev/null
+++ b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs
@@ -0,0 +1,32 @@
+// 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.
+
+// Various tests where we over type parameters with multiple lifetime
+// bounds.
+
+trait SomeTrait { fn get(&self) -> int; }
+
+fn make_object_good1<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'a> {
+    // A outlives 'a AND 'b...
+    box v as Box<SomeTrait+'a> // ...hence this type is safe.
+}
+
+fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'b> {
+    // A outlives 'a AND 'b...
+    box v as Box<SomeTrait+'b> // ...hence this type is safe.
+}
+
+fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'c> {
+    // A outlives 'a AND 'b...but not 'c.
+    box v as Box<SomeTrait+'a> //~ ERROR mismatched types
+}
+
+fn main() {
+}
diff --git a/src/test/run-pass/regions-close-over-type-parameter-successfully.rs b/src/test/run-pass/regions-close-over-type-parameter-successfully.rs
new file mode 100644
index 00000000000..5dba80ad38a
--- /dev/null
+++ b/src/test/run-pass/regions-close-over-type-parameter-successfully.rs
@@ -0,0 +1,30 @@
+// 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.
+
+// A test where we (successfully) close over a reference into
+// an object.
+
+trait SomeTrait { fn get(&self) -> int; }
+
+impl<'a> SomeTrait for &'a int {
+    fn get(&self) -> int {
+        **self
+    }
+}
+
+fn make_object<'a,A:SomeTrait+'a>(v: A) -> Box<SomeTrait+'a> {
+    box v as Box<SomeTrait+'a>
+}
+
+fn main() {
+    let i: int = 22;
+    let obj = make_object(&i);
+    assert_eq!(22, obj.get());
+}