From bdd61f8efde908df8fb59815625d73edc1f95f13 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Sat, 20 Dec 2014 02:48:43 -0800 Subject: [PATCH] Add support for multiple region bounds in where clauses --- src/librustc/middle/resolve_lifetime.rs | 13 ++++-- src/librustc_typeck/collect.rs | 8 ++-- src/libsyntax/ast.rs | 4 +- src/libsyntax/ext/deriving/generic/mod.rs | 2 +- src/libsyntax/fold.rs | 4 +- src/libsyntax/parse/parser.rs | 7 ++-- src/libsyntax/print/pprust.rs | 11 ++++- src/libsyntax/visit.rs | 7 +++- ...ple-lifetime-bounds-on-fns-where-clause.rs | 41 +++++++++++++++++++ 9 files changed, 76 insertions(+), 21 deletions(-) create mode 100644 src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index d0fb4f64a6c5e..be191801626a8 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 { 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 11c89f248b262..3f59b50337faf 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(), ®ion_pred.lifetime); - let r2 = ast_region_to_region(this.tcx(), ®ion_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 13ea5da66c837..440e11e385fe0 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, } -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 c40ccaa31a57b..d8de3d2db9795 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 dd1e8b73f361d..86df588386464 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -824,12 +824,12 @@ pub fn noop_fold_where_predicate( }) } 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 64bcf7dbdd183..d859b79f8d9b2 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 d619a38666497..1522d429c7c57 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 c2a7a0316c7cb..c757b9099cbd2 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 0000000000000..a03911e1d0e18 --- /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 or the MIT license +// , 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() { }