about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs17
-rw-r--r--src/libsyntax/ast_map/mod.rs21
-rw-r--r--src/libsyntax/ast_util.rs10
-rw-r--r--src/libsyntax/ext/deriving/generic/mod.rs8
-rw-r--r--src/libsyntax/ext/deriving/generic/ty.rs9
-rw-r--r--src/libsyntax/fold.rs43
-rw-r--r--src/libsyntax/parse/lexer/mod.rs24
-rw-r--r--src/libsyntax/parse/mod.rs4
-rw-r--r--src/libsyntax/parse/parser.rs92
-rw-r--r--src/libsyntax/parse/token.rs21
-rw-r--r--src/libsyntax/print/pprust.rs139
-rw-r--r--src/libsyntax/visit.rs14
12 files changed, 299 insertions, 103 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 1ff8ca10fff..c658a5c3192 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -245,6 +245,7 @@ pub struct TyParam {
 pub struct Generics {
     pub lifetimes: Vec<LifetimeDef>,
     pub ty_params: OwnedSlice<TyParam>,
+    pub where_clause: WhereClause,
 }
 
 impl Generics {
@@ -259,9 +260,23 @@ impl Generics {
     }
 }
 
+#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
+pub struct WhereClause {
+    pub id: NodeId,
+    pub predicates: Vec<WherePredicate>,
+}
+
+#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
+pub struct WherePredicate {
+    pub id: NodeId,
+    pub span: Span,
+    pub ident: Ident,
+    pub bounds: OwnedSlice<TyParamBound>,
+}
+
 /// The set of MetaItems that define the compilation environment of the crate,
 /// used to drive conditional compilation
-pub type CrateConfig = Vec<Gc<MetaItem>> ;
+pub type CrateConfig = Vec<Gc<MetaItem>>;
 
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
 pub struct Crate {
diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs
index 78afa8441c5..5fccf6cc3f0 100644
--- a/src/libsyntax/ast_map/mod.rs
+++ b/src/libsyntax/ast_map/mod.rs
@@ -431,11 +431,14 @@ impl Map {
     /// the iterator will produce node id's for items with paths
     /// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and
     /// any other such items it can find in the map.
-    pub fn nodes_matching_suffix<'a, S:Str>(&'a self, parts: &'a [S]) -> NodesMatchingSuffix<'a,S> {
-        NodesMatchingSuffix { map: self,
-                              item_name: parts.last().unwrap(),
-                              where: parts.slice_to(parts.len() - 1),
-                              idx: 0 }
+    pub fn nodes_matching_suffix<'a, S:Str>(&'a self, parts: &'a [S])
+                                 -> NodesMatchingSuffix<'a,S> {
+        NodesMatchingSuffix {
+            map: self,
+            item_name: parts.last().unwrap(),
+            in_which: parts.slice_to(parts.len() - 1),
+            idx: 0,
+        }
     }
 
     pub fn opt_span(&self, id: NodeId) -> Option<Span> {
@@ -478,20 +481,20 @@ impl Map {
 pub struct NodesMatchingSuffix<'a, S> {
     map: &'a Map,
     item_name: &'a S,
-    where: &'a [S],
+    in_which: &'a [S],
     idx: NodeId,
 }
 
 impl<'a,S:Str> NodesMatchingSuffix<'a,S> {
     /// Returns true only if some suffix of the module path for parent
-    /// matches `self.where`.
+    /// matches `self.in_which`.
     ///
-    /// In other words: let `[x_0,x_1,...,x_k]` be `self.where`;
+    /// In other words: let `[x_0,x_1,...,x_k]` be `self.in_which`;
     /// returns true if parent's path ends with the suffix
     /// `x_0::x_1::...::x_k`.
     fn suffix_matches(&self, parent: NodeId) -> bool {
         let mut cursor = parent;
-        for part in self.where.iter().rev() {
+        for part in self.in_which.iter().rev() {
             let (mod_id, mod_name) = match find_first_mod_parent(self.map, cursor) {
                 None => return false,
                 Some((node_id, name)) => (node_id, name),
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 7689646d373..5674c6675f9 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -320,8 +320,14 @@ pub fn operator_prec(op: ast::BinOp) -> uint {
 pub static as_prec: uint = 12u;
 
 pub fn empty_generics() -> Generics {
-    Generics {lifetimes: Vec::new(),
-              ty_params: OwnedSlice::empty()}
+    Generics {
+        lifetimes: Vec::new(),
+        ty_params: OwnedSlice::empty(),
+        where_clause: WhereClause {
+            id: DUMMY_NODE_ID,
+            predicates: Vec::new(),
+        }
+    }
 }
 
 // ______________________________________________________________________
diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs
index 7a8ee6d1416..f9f2a86d182 100644
--- a/src/libsyntax/ext/deriving/generic/mod.rs
+++ b/src/libsyntax/ext/deriving/generic/mod.rs
@@ -390,7 +390,7 @@ impl<'a> TraitDef<'a> {
                            methods: Vec<Gc<ast::Method>> ) -> Gc<ast::Item> {
         let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
 
-        let Generics { mut lifetimes, ty_params } =
+        let Generics { mut lifetimes, ty_params, where_clause: _ } =
             self.generics.to_generics(cx, self.span, type_ident, generics);
         let mut ty_params = ty_params.into_vec();
 
@@ -418,7 +418,11 @@ impl<'a> TraitDef<'a> {
         }));
         let trait_generics = Generics {
             lifetimes: lifetimes,
-            ty_params: OwnedSlice::from_vec(ty_params)
+            ty_params: OwnedSlice::from_vec(ty_params),
+            where_clause: ast::WhereClause {
+                id: ast::DUMMY_NODE_ID,
+                predicates: Vec::new(),
+            },
         };
 
         // Create the reference to the trait.
diff --git a/src/libsyntax/ext/deriving/generic/ty.rs b/src/libsyntax/ext/deriving/generic/ty.rs
index 2130b6f4e9d..f4a9b85f75d 100644
--- a/src/libsyntax/ext/deriving/generic/ty.rs
+++ b/src/libsyntax/ext/deriving/generic/ty.rs
@@ -202,10 +202,15 @@ fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str,
     cx.typaram(span, cx.ident_of(name), bounds, unbound, None)
 }
 
-fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam> ) -> Generics {
+fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>)
+               -> Generics {
     Generics {
         lifetimes: lifetimes,
-        ty_params: OwnedSlice::from_vec(ty_params)
+        ty_params: OwnedSlice::from_vec(ty_params),
+        where_clause: ast::WhereClause {
+            id: ast::DUMMY_NODE_ID,
+            predicates: Vec::new(),
+        },
     }
 }
 
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 4ed2a3ed4c2..9ad28f02e80 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -244,6 +244,16 @@ pub trait Folder {
         noop_fold_field(field, self)
     }
 
+    fn fold_where_clause(&mut self, where_clause: &WhereClause)
+                         -> WhereClause {
+        noop_fold_where_clause(where_clause, self)
+    }
+
+    fn fold_where_predicate(&mut self, where_predicate: &WherePredicate)
+                            -> WherePredicate {
+        noop_fold_where_predicate(where_predicate, self)
+    }
+
 // Helper methods:
 
     fn map_exprs(&self, f: |Gc<Expr>| -> Gc<Expr>,
@@ -698,8 +708,37 @@ pub fn noop_fold_opt_lifetime<T: Folder>(o_lt: &Option<Lifetime>, fld: &mut T)
 }
 
 pub fn noop_fold_generics<T: Folder>(generics: &Generics, fld: &mut T) -> Generics {
-    Generics {ty_params: fld.fold_ty_params(generics.ty_params.as_slice()),
-              lifetimes: fld.fold_lifetime_defs(generics.lifetimes.as_slice())}
+    Generics {
+        ty_params: fld.fold_ty_params(generics.ty_params.as_slice()),
+        lifetimes: fld.fold_lifetime_defs(generics.lifetimes.as_slice()),
+        where_clause: fld.fold_where_clause(&generics.where_clause),
+    }
+}
+
+pub fn noop_fold_where_clause<T: Folder>(
+                              where_clause: &WhereClause,
+                              fld: &mut T)
+                              -> WhereClause {
+    WhereClause {
+        id: fld.new_id(where_clause.id),
+        predicates: where_clause.predicates.iter().map(|predicate| {
+            fld.fold_where_predicate(predicate)
+        }).collect(),
+    }
+}
+
+pub fn noop_fold_where_predicate<T: Folder>(
+                                 predicate: &WherePredicate,
+                                 fld: &mut T)
+                                 -> WherePredicate {
+    WherePredicate {
+        id: fld.new_id(predicate.id),
+        span: fld.new_span(predicate.span),
+        ident: fld.fold_ident(predicate.ident),
+        bounds: predicate.bounds.map(|x| {
+            fld.fold_ty_param_bound(x)
+        }),
+    }
 }
 
 pub fn noop_fold_struct_def<T: Folder>(struct_def: Gc<StructDef>,
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index e5275af5cca..17249628989 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -543,7 +543,7 @@ impl<'a> StringReader<'a> {
     // favors rustc debugging effectiveness over runtime efficiency.
 
     /// Scan through input of form \x00name_NNNNNN,ctxt_CCCCCCC\x00
-    /// where: `NNNNNN` is a string of characters forming an integer
+    /// whence: `NNNNNN` is a string of characters forming an integer
     /// (the name) and `CCCCCCC` is a string of characters forming an
     /// integer (the ctxt), separate by a comma and delimited by a
     /// `\x00` marker.
@@ -552,22 +552,22 @@ impl<'a> StringReader<'a> {
         fn bump_expecting_char<'a,D:fmt::Show>(r: &mut StringReader<'a>,
                                                c: char,
                                                described_c: D,
-                                               where: &str) {
+                                               whence: &str) {
             match r.curr {
                 Some(r_c) if r_c == c => r.bump(),
-                Some(r_c) => fail!("expected {}, hit {}, {}", described_c, r_c, where),
-                None      => fail!("expected {}, hit EOF, {}", described_c, where),
+                Some(r_c) => fail!("expected {}, hit {}, {}", described_c, r_c, whence),
+                None      => fail!("expected {}, hit EOF, {}", described_c, whence),
             }
         }
 
-        let where = "while scanning embedded hygienic ident";
+        let whence = "while scanning embedded hygienic ident";
 
         // skip over the leading `\x00`
-        bump_expecting_char(self, '\x00', "nul-byte", where);
+        bump_expecting_char(self, '\x00', "nul-byte", whence);
 
         // skip over the "name_"
         for c in "name_".chars() {
-            bump_expecting_char(self, c, c, where);
+            bump_expecting_char(self, c, c, whence);
         }
 
         let start_bpos = self.last_pos;
@@ -578,16 +578,16 @@ impl<'a> StringReader<'a> {
         let encoded_name : u32 = self.with_str_from(start_bpos, |s| {
             num::from_str_radix(s, 10).unwrap_or_else(|| {
                 fail!("expected digits representing a name, got `{}`, {}, range [{},{}]",
-                      s, where, start_bpos, self.last_pos);
+                      s, whence, start_bpos, self.last_pos);
             })
         });
 
         // skip over the `,`
-        bump_expecting_char(self, ',', "comma", where);
+        bump_expecting_char(self, ',', "comma", whence);
 
         // skip over the "ctxt_"
         for c in "ctxt_".chars() {
-            bump_expecting_char(self, c, c, where);
+            bump_expecting_char(self, c, c, whence);
         }
 
         // find the integer representing the ctxt
@@ -595,12 +595,12 @@ impl<'a> StringReader<'a> {
         self.scan_digits(base);
         let encoded_ctxt : ast::SyntaxContext = self.with_str_from(start_bpos, |s| {
             num::from_str_radix(s, 10).unwrap_or_else(|| {
-                fail!("expected digits representing a ctxt, got `{}`, {}", s, where);
+                fail!("expected digits representing a ctxt, got `{}`, {}", s, whence);
             })
         });
 
         // skip over the `\x00`
-        bump_expecting_char(self, '\x00', "nul-byte", where);
+        bump_expecting_char(self, '\x00', "nul-byte", whence);
 
         ast::Ident { name: ast::Name(encoded_name),
                      ctxt: encoded_ctxt, }
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index af1f296a6ca..271cefeaf03 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -1053,6 +1053,10 @@ mod test {
                                     ast::Generics{ // no idea on either of these:
                                         lifetimes: Vec::new(),
                                         ty_params: OwnedSlice::empty(),
+                                        where_clause: ast::WhereClause {
+                                            id: ast::DUMMY_NODE_ID,
+                                            predicates: Vec::new(),
+                                        }
                                     },
                                     ast::P(ast::Block {
                                         view_items: Vec::new(),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index f272f7e1887..577959ea36a 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -60,7 +60,7 @@ use ast::{UnboxedClosureKind, UnboxedFnTy, UnboxedFnTyParamBound};
 use ast::{UnnamedField, UnsafeBlock};
 use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
 use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
-use ast::Visibility;
+use ast::{Visibility, WhereClause, WherePredicate};
 use ast;
 use ast_util::{as_prec, ident_to_path, lit_is_str, operator_prec};
 use ast_util;
@@ -1264,7 +1264,7 @@ impl<'a> Parser<'a> {
             let style = p.parse_fn_style();
             let ident = p.parse_ident();
 
-            let generics = p.parse_generics();
+            let mut generics = p.parse_generics();
 
             let (explicit_self, d) = p.parse_fn_decl_with_self(|p| {
                 // This is somewhat dubious; We don't want to allow argument
@@ -1272,6 +1272,8 @@ impl<'a> Parser<'a> {
                 p.parse_arg_general(false)
             });
 
+            p.parse_where_clause(&mut generics);
+
             let hi = p.last_span.hi;
             match p.token {
               token::SEMI => {
@@ -3742,7 +3744,10 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Parse a set of optional generic type parameter declarations
+    /// Parse a set of optional generic type parameter declarations. Where
+    /// clauses are not parsed here, and must be added later via
+    /// `parse_where_clause()`.
+    ///
     /// matches generics = ( ) | ( < > ) | ( < typaramseq ( , )? > ) | ( < lifetimes ( , )? > )
     ///                  | ( < lifetimes , typaramseq ( , )? > )
     /// where   typaramseq = ( typaram ) | ( typaram , typaramseq )
@@ -3762,7 +3767,14 @@ impl<'a> Parser<'a> {
                 }
                 ty_param
             });
-            ast::Generics { lifetimes: lifetime_defs, ty_params: ty_params }
+            ast::Generics {
+                lifetimes: lifetime_defs,
+                ty_params: ty_params,
+                where_clause: WhereClause {
+                    id: ast::DUMMY_NODE_ID,
+                    predicates: Vec::new(),
+                }
+            }
         } else {
             ast_util::empty_generics()
         }
@@ -3788,6 +3800,52 @@ impl<'a> Parser<'a> {
         }
     }
 
+    /// Parses an optional `where` clause and places it in `generics`.
+    fn parse_where_clause(&mut self, generics: &mut ast::Generics) {
+        if !self.eat_keyword(keywords::Where) {
+            return
+        }
+
+        let mut parsed_something = false;
+        loop {
+            let lo = self.span.lo;
+            let ident = match self.token {
+                token::IDENT(..) => self.parse_ident(),
+                _ => break,
+            };
+            self.expect(&token::COLON);
+
+            let (_, bounds) = self.parse_ty_param_bounds(false);
+            let hi = self.span.hi;
+            let span = mk_sp(lo, hi);
+
+            if bounds.len() == 0 {
+                self.span_err(span,
+                              "each predicate in a `where` clause must have \
+                               at least one bound in it");
+            }
+
+            generics.where_clause.predicates.push(ast::WherePredicate {
+                id: ast::DUMMY_NODE_ID,
+                span: span,
+                ident: ident,
+                bounds: bounds,
+            });
+            parsed_something = true;
+
+            if !self.eat(&token::COMMA) {
+                break
+            }
+        }
+
+        if !parsed_something {
+            let last_span = self.last_span;
+            self.span_err(last_span,
+                          "a `where` clause must have at least one predicate \
+                           in it");
+        }
+    }
+
     fn parse_fn_args(&mut self, named_args: bool, allow_variadic: bool)
                      -> (Vec<Arg> , bool) {
         let sp = self.span;
@@ -4143,8 +4201,9 @@ impl<'a> Parser<'a> {
 
     /// Parse an item-position function declaration.
     fn parse_item_fn(&mut self, fn_style: FnStyle, abi: abi::Abi) -> ItemInfo {
-        let (ident, generics) = self.parse_fn_header();
+        let (ident, mut generics) = self.parse_fn_header();
         let decl = self.parse_fn_decl(false);
+        self.parse_where_clause(&mut generics);
         let (inner_attrs, body) = self.parse_inner_attrs_and_block();
         (ident, ItemFn(decl, fn_style, abi, generics, body), Some(inner_attrs))
     }
@@ -4200,10 +4259,11 @@ impl<'a> Parser<'a> {
                 };
                 let fn_style = self.parse_fn_style();
                 let ident = self.parse_ident();
-                let generics = self.parse_generics();
+                let mut generics = self.parse_generics();
                 let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| {
                         p.parse_arg()
                     });
+                self.parse_where_clause(&mut generics);
                 let (inner_attrs, body) = self.parse_inner_attrs_and_block();
                 let new_attrs = attrs.append(inner_attrs.as_slice());
                 (ast::MethDecl(ident,
@@ -4228,7 +4288,7 @@ impl<'a> Parser<'a> {
     /// Parse trait Foo { ... }
     fn parse_item_trait(&mut self) -> ItemInfo {
         let ident = self.parse_ident();
-        let tps = self.parse_generics();
+        let mut tps = self.parse_generics();
         let sized = self.parse_for_sized();
 
         // Parse traits, if necessary.
@@ -4240,6 +4300,8 @@ impl<'a> Parser<'a> {
             traits = Vec::new();
         }
 
+        self.parse_where_clause(&mut tps);
+
         let meths = self.parse_trait_methods();
         (ident, ItemTrait(tps, sized, traits, meths), None)
     }
@@ -4261,7 +4323,7 @@ impl<'a> Parser<'a> {
     ///    impl<T> ToString for ~[T] { ... }
     fn parse_item_impl(&mut self) -> ItemInfo {
         // First, parse type parameters if necessary.
-        let generics = self.parse_generics();
+        let mut generics = self.parse_generics();
 
         // Special case: if the next identifier that follows is '(', don't
         // allow this to be parsed as a trait.
@@ -4297,6 +4359,7 @@ impl<'a> Parser<'a> {
             None
         };
 
+        self.parse_where_clause(&mut generics);
         let (impl_items, attrs) = self.parse_impl_items();
 
         let ident = ast_util::impl_pretty_name(&opt_trait, &*ty);
@@ -4326,7 +4389,7 @@ impl<'a> Parser<'a> {
     /// Parse struct Foo { ... }
     fn parse_item_struct(&mut self, is_virtual: bool) -> ItemInfo {
         let class_name = self.parse_ident();
-        let generics = self.parse_generics();
+        let mut generics = self.parse_generics();
 
         let super_struct = if self.eat(&token::COLON) {
             let ty = self.parse_ty(true);
@@ -4343,6 +4406,8 @@ impl<'a> Parser<'a> {
             None
         };
 
+        self.parse_where_clause(&mut generics);
+
         let mut fields: Vec<StructField>;
         let is_tuple_like;
 
@@ -4683,8 +4748,9 @@ impl<'a> Parser<'a> {
         let lo = self.span.lo;
         self.expect_keyword(keywords::Fn);
 
-        let (ident, generics) = self.parse_fn_header();
+        let (ident, mut generics) = self.parse_fn_header();
         let decl = self.parse_fn_decl(true);
+        self.parse_where_clause(&mut generics);
         let hi = self.span.hi;
         self.expect(&token::SEMI);
         box(GC) ast::ForeignItem { ident: ident,
@@ -4834,7 +4900,8 @@ impl<'a> Parser<'a> {
     /// Parse type Foo = Bar;
     fn parse_item_type(&mut self) -> ItemInfo {
         let ident = self.parse_ident();
-        let tps = self.parse_generics();
+        let mut tps = self.parse_generics();
+        self.parse_where_clause(&mut tps);
         self.expect(&token::EQ);
         let ty = self.parse_ty(true);
         self.expect(&token::SEMI);
@@ -4925,7 +4992,8 @@ impl<'a> Parser<'a> {
     /// Parse an "enum" declaration
     fn parse_item_enum(&mut self) -> ItemInfo {
         let id = self.parse_ident();
-        let generics = self.parse_generics();
+        let mut generics = self.parse_generics();
+        self.parse_where_clause(&mut generics);
         self.expect(&token::LBRACE);
 
         let enum_definition = self.parse_enum_def(&generics);
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index f1ef7980151..4c959932f41 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -499,18 +499,19 @@ declare_special_idents_and_keywords! {
         (41,                         Proc,       "proc");
         (42,                         Box,        "box");
         (43,                         Const,      "const");
+        (44,                         Where,      "where");
 
         'reserved:
-        (44,                         Alignof,    "alignof");
-        (45,                         Be,         "be");
-        (46,                         Offsetof,   "offsetof");
-        (47,                         Priv,       "priv");
-        (48,                         Pure,       "pure");
-        (49,                         Sizeof,     "sizeof");
-        (50,                         Typeof,     "typeof");
-        (51,                         Unsized,    "unsized");
-        (52,                         Yield,      "yield");
-        (53,                         Do,         "do");
+        (45,                         Alignof,    "alignof");
+        (46,                         Be,         "be");
+        (47,                         Offsetof,   "offsetof");
+        (48,                         Priv,       "priv");
+        (49,                         Pure,       "pure");
+        (50,                         Sizeof,     "sizeof");
+        (51,                         Typeof,     "typeof");
+        (52,                         Unsized,    "unsized");
+        (53,                         Yield,      "yield");
+        (54,                         Do,         "do");
     }
 }
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index c573cc0c0ad..998049b83cc 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -584,7 +584,11 @@ impl<'a> State<'a> {
             ast::TyBareFn(f) => {
                 let generics = ast::Generics {
                     lifetimes: f.lifetimes.clone(),
-                    ty_params: OwnedSlice::empty()
+                    ty_params: OwnedSlice::empty(),
+                    where_clause: ast::WhereClause {
+                        id: ast::DUMMY_NODE_ID,
+                        predicates: Vec::new(),
+                    },
                 };
                 try!(self.print_ty_fn(Some(f.abi),
                                       None,
@@ -601,7 +605,11 @@ impl<'a> State<'a> {
             ast::TyClosure(f, ref region) => {
                 let generics = ast::Generics {
                     lifetimes: f.lifetimes.clone(),
-                    ty_params: OwnedSlice::empty()
+                    ty_params: OwnedSlice::empty(),
+                    where_clause: ast::WhereClause {
+                        id: ast::DUMMY_NODE_ID,
+                        predicates: Vec::new(),
+                    },
                 };
                 try!(self.print_ty_fn(None,
                                       Some('&'),
@@ -618,7 +626,11 @@ impl<'a> State<'a> {
             ast::TyProc(ref f) => {
                 let generics = ast::Generics {
                     lifetimes: f.lifetimes.clone(),
-                    ty_params: OwnedSlice::empty()
+                    ty_params: OwnedSlice::empty(),
+                    where_clause: ast::WhereClause {
+                        id: ast::DUMMY_NODE_ID,
+                        predicates: Vec::new(),
+                    },
                 };
                 try!(self.print_ty_fn(None,
                                       Some('~'),
@@ -765,6 +777,7 @@ impl<'a> State<'a> {
                 try!(space(&mut self.s));
                 try!(self.word_space("="));
                 try!(self.print_type(&**ty));
+                try!(self.print_where_clause(params));
                 try!(word(&mut self.s, ";"));
                 try!(self.end()); // end the outer ibox
             }
@@ -808,6 +821,7 @@ impl<'a> State<'a> {
                 }
 
                 try!(self.print_type(&**ty));
+                try!(self.print_where_clause(generics));
 
                 try!(space(&mut self.s));
                 try!(self.bopen());
@@ -845,6 +859,7 @@ impl<'a> State<'a> {
                         try!(self.print_path(&trait_.path, false));
                     }
                 }
+                try!(self.print_where_clause(generics));
                 try!(word(&mut self.s, " "));
                 try!(self.bopen());
                 for meth in methods.iter() {
@@ -880,6 +895,7 @@ impl<'a> State<'a> {
         try!(self.head(visibility_qualified(visibility, "enum").as_slice()));
         try!(self.print_ident(ident));
         try!(self.print_generics(generics));
+        try!(self.print_where_clause(generics));
         try!(space(&mut self.s));
         self.print_variants(enum_definition.variants.as_slice(), span)
     }
@@ -2010,7 +2026,8 @@ impl<'a> State<'a> {
         try!(self.nbsp());
         try!(self.print_ident(name));
         try!(self.print_generics(generics));
-        self.print_fn_args_and_ret(decl, opt_explicit_self)
+        try!(self.print_fn_args_and_ret(decl, opt_explicit_self))
+        self.print_where_clause(generics)
     }
 
     pub fn print_fn_args(&mut self, decl: &ast::FnDecl,
@@ -2201,54 +2218,83 @@ impl<'a> State<'a> {
         Ok(())
     }
 
-    pub fn print_generics(&mut self,
-                          generics: &ast::Generics) -> IoResult<()> {
-        let total = generics.lifetimes.len() + generics.ty_params.len();
-        if total > 0 {
-            try!(word(&mut self.s, "<"));
+    fn print_type_parameters(&mut self,
+                             lifetimes: &[ast::LifetimeDef],
+                             ty_params: &[ast::TyParam])
+                             -> IoResult<()> {
+        let total = lifetimes.len() + ty_params.len();
+        let mut ints = Vec::new();
+        for i in range(0u, total) {
+            ints.push(i);
+        }
 
-            let mut ints = Vec::new();
-            for i in range(0u, total) {
-                ints.push(i);
-            }
-
-            try!(self.commasep(
-                Inconsistent, ints.as_slice(),
-                |s, &idx| {
-                    if idx < generics.lifetimes.len() {
-                        let lifetime = generics.lifetimes.get(idx);
-                        s.print_lifetime_def(lifetime)
-                    } else {
-                        let idx = idx - generics.lifetimes.len();
-                        let param = generics.ty_params.get(idx);
-                        match param.unbound {
-                            Some(TraitTyParamBound(ref tref)) => {
-                                try!(s.print_trait_ref(tref));
-                                try!(s.word_space("?"));
-                            }
-                            _ => {}
-                        }
-                        try!(s.print_ident(param.ident));
-                        try!(s.print_bounds(&None,
-                                            &param.bounds,
-                                            false,
-                                            false));
-                        match param.default {
-                            Some(ref default) => {
-                                try!(space(&mut s.s));
-                                try!(s.word_space("="));
-                                s.print_type(&**default)
-                            }
-                            _ => Ok(())
-                        }
+        self.commasep(Inconsistent, ints.as_slice(), |s, &idx| {
+            if idx < lifetimes.len() {
+                let lifetime = &lifetimes[idx];
+                s.print_lifetime_def(lifetime)
+            } else {
+                let idx = idx - lifetimes.len();
+                let param = &ty_params[idx];
+                match param.unbound {
+                    Some(TraitTyParamBound(ref tref)) => {
+                        try!(s.print_trait_ref(tref));
+                        try!(s.word_space("?"));
                     }
-                }));
+                    _ => {}
+                }
+                try!(s.print_ident(param.ident));
+                try!(s.print_bounds(&None,
+                                    &param.bounds,
+                                    false,
+                                    false));
+                match param.default {
+                    Some(ref default) => {
+                        try!(space(&mut s.s));
+                        try!(s.word_space("="));
+                        s.print_type(&**default)
+                    }
+                    _ => Ok(())
+                }
+            }
+        })
+    }
+
+    pub fn print_generics(&mut self, generics: &ast::Generics)
+                          -> IoResult<()> {
+        if generics.lifetimes.len() + generics.ty_params.len() > 0 {
+            try!(word(&mut self.s, "<"));
+            try!(self.print_type_parameters(generics.lifetimes.as_slice(),
+                                            generics.ty_params.as_slice()));
             word(&mut self.s, ">")
         } else {
             Ok(())
         }
     }
 
+    pub fn print_where_clause(&mut self, generics: &ast::Generics)
+                              -> IoResult<()> {
+        if generics.where_clause.predicates.len() == 0 {
+            return Ok(())
+        }
+
+        try!(space(&mut self.s));
+        try!(self.word_space("where"));
+
+        for (i, predicate) in generics.where_clause
+                                      .predicates
+                                      .iter()
+                                      .enumerate() {
+            if i != 0 {
+                try!(self.word_space(","));
+            }
+
+            try!(self.print_ident(predicate.ident));
+            try!(self.print_bounds(&None, &predicate.bounds, false, false));
+        }
+
+        Ok(())
+    }
+
     pub fn print_meta_item(&mut self, item: &ast::MetaItem) -> IoResult<()> {
         try!(self.ibox(indent_unit));
         match item.node {
@@ -2472,6 +2518,11 @@ impl<'a> State<'a> {
             }
         }
 
+        match generics {
+            Some(generics) => try!(self.print_where_clause(generics)),
+            None => {}
+        }
+
         self.end()
     }
 
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 18cbf797d03..ac1dbdc439c 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -27,6 +27,7 @@
 use abi::Abi;
 use ast::*;
 use ast;
+use ast_util;
 use codemap::Span;
 use parse;
 use owned_slice::OwnedSlice;
@@ -58,12 +59,7 @@ pub fn generics_of_fn(fk: &FnKind) -> Generics {
         FkMethod(_, generics, _) => {
             (*generics).clone()
         }
-        FkFnBlock(..) => {
-            Generics {
-                lifetimes: Vec::new(),
-                ty_params: OwnedSlice::empty(),
-            }
-        }
+        FkFnBlock(..) => ast_util::empty_generics(),
     }
 }
 
@@ -559,7 +555,11 @@ pub fn walk_generics<E: Clone, V: Visitor<E>>(visitor: &mut V,
             None => {}
         }
     }
-    walk_lifetime_decls(visitor, &generics.lifetimes, env);
+    walk_lifetime_decls(visitor, &generics.lifetimes, env.clone());
+    for predicate in generics.where_clause.predicates.iter() {
+        visitor.visit_ident(predicate.span, predicate.ident, env.clone());
+        walk_ty_param_bounds(visitor, &predicate.bounds, env.clone());
+    }
 }
 
 pub fn walk_fn_decl<E: Clone, V: Visitor<E>>(visitor: &mut V,