about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJared Roesch <roeschinc@gmail.com>2014-12-20 02:48:43 -0800
committerJared Roesch <roeschinc@gmail.com>2014-12-20 03:54:39 -0800
commitd87b308b67ab070d67ab66062b33f64e5bc621e4 (patch)
tree13fa47333d28c9926b8a26718f355250ad20247d
parente0cac488ac6ca16507da390429565b7879f76bb4 (diff)
Add support for multiple region bounds in where clauses
-rw-r--r--src/librustc/middle/resolve_lifetime.rs13
-rw-r--r--src/librustc_typeck/collect.rs8
-rw-r--r--src/libsyntax/ast.rs4
-rw-r--r--src/libsyntax/ext/deriving/generic/mod.rs2
-rw-r--r--src/libsyntax/fold.rs4
-rw-r--r--src/libsyntax/parse/parser.rs7
-rw-r--r--src/libsyntax/print/pprust.rs11
-rw-r--r--src/libsyntax/visit.rs7
-rw-r--r--src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs41
-rw-r--r--src/test/compile-fail/where-clause-method-substituion.rs4
-rw-r--r--src/test/compile-fail/where-clauses-method-unsatisfied.rs2
11 files changed, 79 insertions, 24 deletions
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index d0fb4f64a6c..be191801626 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -213,11 +213,13 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
                     visit::walk_ty_param_bounds_helper(self, bounds);
                 }
                 &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
-                                                                                ref bound,
+                                                                                ref bounds,
                                                                                 .. }) => {
 
                     self.visit_lifetime_ref(lifetime);
-                    self.visit_lifetime_ref(bound);
+                    for bound in bounds.iter() {
+                        self.visit_lifetime_ref(bound);
+                    }
                 }
                 &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ id,
                                                                          ref path,
@@ -558,10 +560,13 @@ fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec<ast::Name> {
                     visit::walk_ty_param_bounds_helper(&mut collector, bounds);
                 }
                 &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
-                                                                                ref bound,
+                                                                                ref bounds,
                                                                                 ..}) => {
                     collector.visit_lifetime_ref(lifetime);
-                    collector.visit_lifetime_ref(bound);
+
+                    for bound in bounds.iter() {
+                        collector.visit_lifetime_ref(bound);
+                    }
                 }
                 &ast::WherePredicate::EqPredicate(_) => unimplemented!()
             }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 11c89f248b2..3f59b50337f 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1827,9 +1827,11 @@ fn ty_generics<'tcx,AC>(this: &AC,
 
             &ast::WherePredicate::RegionPredicate(ref region_pred) => {
                 let r1 = ast_region_to_region(this.tcx(), &region_pred.lifetime);
-                let r2 = ast_region_to_region(this.tcx(), &region_pred.bound);
-                let pred = ty::Binder(ty::OutlivesPredicate(r1, r2));
-                result.predicates.push(space, ty::Predicate::RegionOutlives(pred))
+                for bound in region_pred.bounds.iter() {
+                    let r2 = ast_region_to_region(this.tcx(), bound);
+                    let pred = ty::Binder(ty::OutlivesPredicate(r1, r2));
+                    result.predicates.push(space, ty::Predicate::RegionOutlives(pred))
+                }
             }
 
             &ast::WherePredicate::EqPredicate(ref eq_pred) => {
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 13ea5da66c8..440e11e385f 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -430,11 +430,9 @@ pub struct WhereBoundPredicate {
 pub struct WhereRegionPredicate {
     pub span: Span,
     pub lifetime: Lifetime,
-    pub bound: Lifetime
+    pub bounds: Vec<Lifetime>,
 }
 
-impl Copy for WhereRegionPredicate {}
-
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
 pub struct WhereEqPredicate {
     pub id: NodeId,
diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs
index c40ccaa31a5..d8de3d2db97 100644
--- a/src/libsyntax/ext/deriving/generic/mod.rs
+++ b/src/libsyntax/ext/deriving/generic/mod.rs
@@ -435,7 +435,7 @@ impl<'a> TraitDef<'a> {
                     ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
                         span: self.span,
                         lifetime: rb.lifetime,
-                        bound: rb.bound
+                        bounds: rb.bounds.iter().map(|b| b.clone()).collect()
                     })
                 }
                 ast::WherePredicate::EqPredicate(ref we) => {
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index dd1e8b73f36..86df5883864 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -824,12 +824,12 @@ pub fn noop_fold_where_predicate<T: Folder>(
             })
         }
         ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{lifetime,
-                                                                       bound,
+                                                                       bounds,
                                                                        span}) => {
             ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
                 span: fld.new_span(span),
                 lifetime: fld.fold_lifetime(lifetime),
-                bound: fld.fold_lifetime(bound)
+                bounds: bounds.move_map(|bound| fld.fold_lifetime(bound))
             })
         }
         ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{id,
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 64bcf7dbdd1..f8b47e0405f 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -4199,9 +4199,8 @@ impl<'a> Parser<'a> {
 
                     self.eat(&token::Colon);
 
-                    // FIXME(#20049)
-                    let bounding_lifetime =
-                        self.parse_lifetime();
+                    let bounds =
+                        self.parse_lifetimes(token::BinOp(token::Plus));
 
                     let hi = self.span.hi;
                     let span = mk_sp(lo, hi);
@@ -4210,7 +4209,7 @@ impl<'a> Parser<'a> {
                         ast::WhereRegionPredicate {
                             span: span,
                             lifetime: bounded_lifetime,
-                            bound: bounding_lifetime
+                            bounds: bounds
                         }
                     ));
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index d619a386664..f27a476dbdd 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -2444,11 +2444,18 @@ impl<'a> State<'a> {
                     try!(self.print_bounds(":", bounds.as_slice()));
                 }
                 &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
-                                                                                ref bound,
+                                                                                ref bounds,
                                                                                 ..}) => {
                     try!(self.print_lifetime(lifetime));
                     try!(word(&mut self.s, ":"));
-                    try!(self.print_lifetime(bound));
+
+                    for (i, bound) in bounds.iter().enumerate() {
+                        try!(self.print_lifetime(bound));
+
+                        if i != 0 {
+                            try!(word(&mut self.s, ":"));
+                        }
+                    }
                 }
                 &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => {
                     try!(self.print_path(path, false));
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index c2a7a0316c7..9938feb171e 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -590,10 +590,13 @@ pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics
                 walk_ty_param_bounds_helper(visitor, bounds);
             }
             &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
-                                                                            ref bound,
+                                                                            ref bounds,
                                                                             ..}) => {
                 visitor.visit_lifetime_ref(lifetime);
-                visitor.visit_lifetime_ref(bound);
+
+                for bound in bounds.iter() {
+                    visitor.visit_lifetime_ref(bound);
+                }
             }
             &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{id,
                                                                     ref path,
diff --git a/src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs b/src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs
new file mode 100644
index 00000000000..a03911e1d0e
--- /dev/null
+++ b/src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs
@@ -0,0 +1,41 @@
+// 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.
+
+fn a<'a, 'b, 'c>(x: &mut &'a int, y: &mut &'b int, z: &mut &'c int) where 'b: 'a + 'c {
+    // Note: this is legal because of the `'b:'a` declaration.
+    *x = *y;
+    *z = *y;
+}
+
+fn b<'a, 'b, 'c>(x: &mut &'a int, y: &mut &'b int, z: &mut &'c int) {
+    // Illegal now because there is no `'b:'a` declaration.
+    *x = *y; //~ ERROR mismatched types
+    *z = *y; //~ ERROR mismatched types
+}
+
+fn c<'a,'b, 'c>(x: &mut &'a int, y: &mut &'b int, z: &mut &'c int) {
+    // Here we try to call `foo` but do not know that `'a` and `'b` are
+    // related as required.
+    a(x, y, z); //~ ERROR cannot infer
+}
+
+fn d() {
+    // 'a and 'b are early bound in the function `a` because they appear
+    // inconstraints:
+    let _: fn(&mut &int, &mut &int, &mut &int) = a; //~ ERROR mismatched types
+}
+
+fn e() {
+    // 'a and 'b are late bound in the function `b` because there are
+    // no constraints:
+    let _: fn(&mut &int, &mut &int, &mut &int) = b;
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/where-clause-method-substituion.rs b/src/test/compile-fail/where-clause-method-substituion.rs
index 2fe7ab9577b..40d2df45488 100644
--- a/src/test/compile-fail/where-clause-method-substituion.rs
+++ b/src/test/compile-fail/where-clause-method-substituion.rs
@@ -26,5 +26,5 @@ impl Bar<X> for int {
 
 fn main() {
     1.method::<X>();
-    //~^ ERROR the trait `Foo<_>` is not implemented for the type `X`
-}
\ No newline at end of file
+    //~^ ERROR the trait `Foo<X>` is not implemented for the type `X`
+}
diff --git a/src/test/compile-fail/where-clauses-method-unsatisfied.rs b/src/test/compile-fail/where-clauses-method-unsatisfied.rs
index a74095bcdf1..e5b54582e4e 100644
--- a/src/test/compile-fail/where-clauses-method-unsatisfied.rs
+++ b/src/test/compile-fail/where-clauses-method-unsatisfied.rs
@@ -26,5 +26,5 @@ impl<T> Foo<T> {
 fn main() {
     let x = Foo { value: Bar };
     x.equals(&x);
-    //~^ ERROR the trait `core::cmp::Eq` is not not implemented
+    //~^ ERROR the trait `core::cmp::Eq` is not implemented for the type `Bar`
 }