]> git.lizzy.rs Git - rust.git/commitdiff
Generalize lifetime bounds on type parameters to support multiple
authorNiko Matsakis <niko@alum.mit.edu>
Thu, 14 Aug 2014 22:05:27 +0000 (18:05 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Tue, 16 Sep 2014 18:18:06 +0000 (14:18 -0400)
lifetime bounds. This doesn't really cause any difficulties, because
we already had to accommodate the fact that multiple implicit bounds
could accumulate. Object types still require precisely one lifetime
bound. This is a pre-step towards generalized where clauses (once you
have lifetime bounds in where clauses, it is harder to restrict them
to exactly one).

src/librustc/metadata/tydecode.rs
src/librustc/metadata/tyencode.rs
src/librustc/middle/ty.rs
src/librustc/middle/ty_fold.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/check/regionck.rs
src/librustc/middle/typeck/check/regionmanip.rs
src/librustc/middle/typeck/collect.rs
src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs
src/test/compile-fail/regions-close-over-type-parameter-multiple.rs [new file with mode: 0644]
src/test/run-pass/regions-close-over-type-parameter-successfully.rs [new file with mode: 0644]

index 53203663bb16e080e48165af52a69b12c7bf6406..0e888b39b8516f5d3fd3a4f1a443058c4b142aab 100644 (file)
@@ -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))));
index cbf558b6b483e615630ae6fd2640e1de7249f580..3ef1d15cf5651eafa635a51b8659087f62f24d33 100644 (file)
@@ -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);
     }
index d0b94cb3abb8b12f8500b247dbdd3639e20a6bc9..628665457cc91a6225b3ff1c2b1ccbeb463b33da 100644 (file)
@@ -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,
@@ -4864,7 +4865,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={}",
index 549f0daef81121c838cff4accc38634c95fc0350..48fa6f823b0e5c8fe232f08328dc494a87ad7037 100644 (file)
@@ -287,7 +287,7 @@ fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Existentia
 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),
         }
index 20fe8186adf40fe50100022eb2ae24fae60d0cf8..ec2c3d2d2efb2dfbb7109805c22ff9ad821ec411 100644 (file)
@@ -2005,7 +2005,7 @@ fn add_region_obligations_for_type_parameter(&self,
         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() {
index 45ffddf3fe80e57d881a9526dc3727149a7dfce7..6926d9dd0e7e72c3ce4c38037ed9bde55c552f11 100644 (file)
@@ -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());
 
index 60e502786ab3dbeb684efd32ac3fe64dcc73114a..8bcbe4b7929852d2dfa85145679e559552c68e48 100644 (file)
@@ -327,7 +327,7 @@ fn accumulate_from_adt(&mut self,
 
                 // 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();
index 581bd8acbc97ea7053908fbc0e6c415dd5be9f38..74db36ff9ac370bdf1502d8fa938cad0a10b77ff 100644 (file)
@@ -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,
     }
index 40cff3e466b7123eb8d85b1fe703b685183a3ce0..6b3c92e0028bf6e1e3ac2fcdfe1abc1432a522ae 100644 (file)
@@ -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 (file)
index 0000000..cec785c
--- /dev/null
@@ -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 (file)
index 0000000..5dba80a
--- /dev/null
@@ -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());
+}