Skip to content

Commit

Permalink
Add support for multiple region bounds in where clauses
Browse files Browse the repository at this point in the history
  • Loading branch information
jroesch committed Dec 20, 2014
1 parent e0cac48 commit bdd61f8
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 21 deletions.
13 changes: 9 additions & 4 deletions src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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!()
}
Expand Down
8 changes: 5 additions & 3 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
4 changes: 1 addition & 3 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ext/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
4 changes: 2 additions & 2 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
7 changes: 3 additions & 4 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -4210,7 +4209,7 @@ impl<'a> Parser<'a> {
ast::WhereRegionPredicate {
span: span,
lifetime: bounded_lifetime,
bound: bounding_lifetime
bounds: bounds
}
));

Expand Down
11 changes: 9 additions & 2 deletions src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
7 changes: 5 additions & 2 deletions src/libsyntax/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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() { }

5 comments on commit bdd61f8

@bors
Copy link
Contributor

@bors bors commented on bdd61f8 Dec 20, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from nikomatsakis
at jroesch@bdd61f8

@bors
Copy link
Contributor

@bors bors commented on bdd61f8 Dec 20, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging jroesch/rust/generalized-where-clause-parser = bdd61f8 into auto

@bors
Copy link
Contributor

@bors bors commented on bdd61f8 Dec 20, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

status: {"merge_sha": "510307976d27823456111186cc6a308144372983"}

@bors
Copy link
Contributor

@bors bors commented on bdd61f8 Dec 20, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jroesch/rust/generalized-where-clause-parser = bdd61f8 merged ok, testing candidate = 51030797

Please sign in to comment.