about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-06-06 03:56:22 +0000
committerbors <bors@rust-lang.org>2019-06-06 03:56:22 +0000
commit740668dbd99dbf1726bbb0cca6cd0943ea2f7e27 (patch)
tree7fcf783b5f92803e8ca4985eaa24097e76b6192c /src/libsyntax
parent1bec46c9a5399d5e95c05e3428c3abd264780705 (diff)
parentee890331f6e33afe12ef250eb6388db2aab7cbbf (diff)
downloadrust-740668dbd99dbf1726bbb0cca6cd0943ea2f7e27.tar.gz
rust-740668dbd99dbf1726bbb0cca6cd0943ea2f7e27.zip
Auto merge of #57428 - alexreg:associated_type_bounds, r=nikomatsakis,Centril
Implementation of RFC 2289 (associated_type_bounds)

This PR implements the [`asociated_type_bounds` feature](https://github.com/rust-lang/rfcs/blob/master/text/2289-associated-type-bounds.md).

Associated type bounds are implemented in:
   - function/method arguments and return types
   - structs, enums, unions
   - associated items in traits
   - type aliases
   - type parameter defaults
   - trait objects
   - let bindings

CC @nikomatsakis @centril
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs32
-rw-r--r--src/libsyntax/ext/build.rs49
-rw-r--r--src/libsyntax/feature_gate.rs42
-rw-r--r--src/libsyntax/mut_visit.rs23
-rw-r--r--src/libsyntax/parse/parser.rs110
-rw-r--r--src/libsyntax/print/pprust.rs23
-rw-r--r--src/libsyntax/ptr.rs3
-rw-r--r--src/libsyntax/util/node_count.rs4
-rw-r--r--src/libsyntax/visit.rs23
9 files changed, 186 insertions, 123 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index b8a10d90c3c..598232f9f8f 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -190,9 +190,9 @@ pub struct AngleBracketedArgs {
     pub span: Span,
     /// The arguments for this path segment.
     pub args: Vec<GenericArg>,
-    /// Bindings (equality constraints) on associated types, if present.
-    /// E.g., `Foo<A = Bar>`.
-    pub bindings: Vec<TypeBinding>,
+    /// Constraints on associated types, if any.
+    /// E.g., `Foo<A = Bar, B: Baz>`.
+    pub constraints: Vec<AssocTyConstraint>,
 }
 
 impl Into<Option<P<GenericArgs>>> for AngleBracketedArgs {
@@ -213,7 +213,7 @@ pub struct ParenthesizedArgs {
     /// Overall span
     pub span: Span,
 
-    /// `(A,B)`
+    /// `(A, B)`
     pub inputs: Vec<P<Ty>>,
 
     /// `C`
@@ -225,7 +225,7 @@ impl ParenthesizedArgs {
         AngleBracketedArgs {
             span: self.span,
             args: self.inputs.iter().cloned().map(|input| GenericArg::Type(input)).collect(),
-            bindings: vec![],
+            constraints: vec![],
         }
     }
 }
@@ -1611,15 +1611,29 @@ impl fmt::Display for UintTy {
     }
 }
 
-// Bind a type to an associated type: `A = Foo`.
+/// A constraint on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
+/// `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`).
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub struct TypeBinding {
+pub struct AssocTyConstraint {
     pub id: NodeId,
     pub ident: Ident,
-    pub ty: P<Ty>,
+    pub kind: AssocTyConstraintKind,
     pub span: Span,
 }
 
+/// The kinds of an `AssocTyConstraint`.
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+pub enum AssocTyConstraintKind {
+    /// E.g., `A = Bar` in `Foo<A = Bar>`.
+    Equality {
+        ty: P<Ty>,
+    },
+    /// E.g. `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`.
+    Bound {
+        bounds: GenericBounds,
+    },
+}
+
 #[derive(Clone, RustcEncodable, RustcDecodable)]
 pub struct Ty {
     pub id: NodeId,
@@ -1840,7 +1854,7 @@ impl Arg {
     }
 }
 
-/// Header (not the body) of a function declaration.
+/// A header (not the body) of a function declaration.
 ///
 /// E.g., `fn foo(bar: baz)`.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 47c79f8466a..2a03e49996b 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -10,7 +10,7 @@ use rustc_target::spec::abi::Abi;
 use syntax_pos::{Pos, Span};
 
 pub trait AstBuilder {
-    // paths
+    // Paths
     fn path(&self, span: Span, strs: Vec<ast::Ident> ) -> ast::Path;
     fn path_ident(&self, span: Span, id: ast::Ident) -> ast::Path;
     fn path_global(&self, span: Span, strs: Vec<ast::Ident> ) -> ast::Path;
@@ -18,7 +18,7 @@ pub trait AstBuilder {
                 global: bool,
                 idents: Vec<ast::Ident>,
                 args: Vec<ast::GenericArg>,
-                bindings: Vec<ast::TypeBinding>)
+                constraints: Vec<ast::AssocTyConstraint>)
         -> ast::Path;
 
     fn qpath(&self, self_type: P<ast::Ty>,
@@ -29,7 +29,7 @@ pub trait AstBuilder {
                 trait_path: ast::Path,
                 ident: ast::Ident,
                 args: Vec<ast::GenericArg>,
-                bindings: Vec<ast::TypeBinding>)
+                constraints: Vec<ast::AssocTyConstraint>)
                 -> (ast::QSelf, ast::Path);
 
     // types and consts
@@ -69,7 +69,7 @@ pub trait AstBuilder {
                     bounds: ast::GenericBounds)
                     -> ast::GenericParam;
 
-    // statements
+    // Statements
     fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt;
     fn stmt_semi(&self, expr: P<ast::Expr>) -> ast::Stmt;
     fn stmt_let(&self, sp: Span, mutbl: bool, ident: ast::Ident, ex: P<ast::Expr>) -> ast::Stmt;
@@ -83,11 +83,11 @@ pub trait AstBuilder {
     fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt;
     fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt;
 
-    // blocks
+    // Blocks
     fn block(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Block>;
     fn block_expr(&self, expr: P<ast::Expr>) -> P<ast::Block>;
 
-    // expressions
+    // Expressions
     fn expr(&self, span: Span, node: ast::ExprKind) -> P<ast::Expr>;
     fn expr_path(&self, path: ast::Path) -> P<ast::Expr>;
     fn expr_qpath(&self, span: Span, qself: ast::QSelf, path: ast::Path) -> P<ast::Expr>;
@@ -194,12 +194,12 @@ pub trait AstBuilder {
     fn lambda_stmts_1(&self, span: Span, stmts: Vec<ast::Stmt>,
                       ident: ast::Ident) -> P<ast::Expr>;
 
-    // items
+    // Items
     fn item(&self, span: Span,
             name: Ident, attrs: Vec<ast::Attribute> , node: ast::ItemKind) -> P<ast::Item>;
 
     fn arg(&self, span: Span, name: Ident, ty: P<ast::Ty>) -> ast::Arg;
-    // FIXME unused self
+    // FIXME: unused `self`
     fn fn_decl(&self, inputs: Vec<ast::Arg> , output: ast::FunctionRetTy) -> P<ast::FnDecl>;
 
     fn item_fn_poly(&self,
@@ -302,7 +302,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
                 global: bool,
                 mut idents: Vec<ast::Ident> ,
                 args: Vec<ast::GenericArg>,
-                bindings: Vec<ast::TypeBinding> )
+                constraints: Vec<ast::AssocTyConstraint> )
                 -> ast::Path {
         assert!(!idents.is_empty());
         let add_root = global && !idents[0].is_path_segment_keyword();
@@ -314,8 +314,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         segments.extend(idents.into_iter().map(|ident| {
             ast::PathSegment::from_ident(ident.with_span_pos(span))
         }));
-        let args = if !args.is_empty() || !bindings.is_empty() {
-            ast::AngleBracketedArgs { args, bindings, span }.into()
+        let args = if !args.is_empty() || !constraints.is_empty() {
+            ast::AngleBracketedArgs { args, constraints, span }.into()
         } else {
             None
         };
@@ -346,11 +346,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
                  trait_path: ast::Path,
                  ident: ast::Ident,
                  args: Vec<ast::GenericArg>,
-                 bindings: Vec<ast::TypeBinding>)
+                 constraints: Vec<ast::AssocTyConstraint>)
                  -> (ast::QSelf, ast::Path) {
         let mut path = trait_path;
-        let args = if !args.is_empty() || !bindings.is_empty() {
-            ast::AngleBracketedArgs { args, bindings, span: ident.span }.into()
+        let args = if !args.is_empty() || !constraints.is_empty() {
+            ast::AngleBracketedArgs { args, constraints, span: ident.span }.into()
         } else {
             None
         };
@@ -552,7 +552,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         }
     }
 
-    // Generate `let _: Type;`, usually used for type assertions.
+    // Generates `let _: Type;`, which is usually used for type assertions.
     fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt {
         let local = P(ast::Local {
             pat: self.pat_wild(span),
@@ -606,7 +606,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         self.expr(path.span, ast::ExprKind::Path(None, path))
     }
 
-    /// Constructs a QPath expression.
+    /// Constructs a `QPath` expression.
     fn expr_qpath(&self, span: Span, qself: ast::QSelf, path: ast::Path) -> P<ast::Expr> {
         self.expr(span, ast::ExprKind::Path(Some(qself), path))
     }
@@ -736,7 +736,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         self.expr(sp, ast::ExprKind::Cast(expr, ty))
     }
 
-
     fn expr_some(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
         let some = self.std_path(&[sym::option, sym::Option, sym::Some]);
         self.expr_call_global(sp, some, vec![expr])
@@ -748,12 +747,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         self.expr_path(none)
     }
 
-
     fn expr_break(&self, sp: Span) -> P<ast::Expr> {
         self.expr(sp, ast::ExprKind::Break(None, None))
     }
 
-
     fn expr_tuple(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
         self.expr(sp, ast::ExprKind::Tup(exprs))
     }
@@ -797,22 +794,22 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         let binding_pat = self.pat_ident(sp, binding_variable);
         let binding_expr = self.expr_ident(sp, binding_variable);
 
-        // Ok(__try_var) pattern
+        // `Ok(__try_var)` pattern
         let ok_pat = self.pat_tuple_struct(sp, ok_path, vec![binding_pat.clone()]);
 
-        // Err(__try_var)  (pattern and expression resp.)
+        // `Err(__try_var)` (pattern and expression respectively)
         let err_pat = self.pat_tuple_struct(sp, err_path.clone(), vec![binding_pat]);
         let err_inner_expr = self.expr_call(sp, self.expr_path(err_path),
                                             vec![binding_expr.clone()]);
-        // return Err(__try_var)
+        // `return Err(__try_var)`
         let err_expr = self.expr(sp, ast::ExprKind::Ret(Some(err_inner_expr)));
 
-        // Ok(__try_var) => __try_var
+        // `Ok(__try_var) => __try_var`
         let ok_arm = self.arm(sp, vec![ok_pat], binding_expr);
-        // Err(__try_var) => return Err(__try_var)
+        // `Err(__try_var) => return Err(__try_var)`
         let err_arm = self.arm(sp, vec![err_pat], err_expr);
 
-        // match head { Ok() => ..., Err() => ... }
+        // `match head { Ok() => ..., Err() => ... }`
         self.expr_match(sp, head, vec![ok_arm, err_arm])
     }
 
@@ -972,7 +969,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         }
     }
 
-    // FIXME unused self
+    // FIXME: unused `self`
     fn fn_decl(&self, inputs: Vec<ast::Arg>, output: ast::FunctionRetTy) -> P<ast::FnDecl> {
         P(ast::FnDecl {
             inputs,
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index b2646efe3e4..4a95b6f69a1 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -15,7 +15,10 @@
 use AttributeType::*;
 use AttributeGate::*;
 
-use crate::ast::{self, NodeId, GenericParam, GenericParamKind, PatKind, RangeEnd};
+use crate::ast::{
+    self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind,
+    PatKind, RangeEnd,
+};
 use crate::attr;
 use crate::early_buffered_lints::BufferedEarlyLintId;
 use crate::source_map::Spanned;
@@ -554,6 +557,9 @@ declare_features! (
     // Allows using C-variadics.
     (active, c_variadic, "1.34.0", Some(44930), None),
 
+    // Allows the user of associated type bounds.
+    (active, associated_type_bounds, "1.34.0", Some(52662), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
@@ -1917,7 +1923,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             self.builtin_attributes.get(&ident.name).map(|a| *a)
         });
 
-        // check for gated attributes
+        // Check for gated attributes.
         self.context.check_attribute(attr, attr_info, false);
 
         if attr.check_name(sym::doc) {
@@ -2115,7 +2121,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
         if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
             if let ast::TyKind::Never = output_ty.node {
-                // Do nothing
+                // Do nothing.
             } else {
                 self.visit_ty(output_ty)
             }
@@ -2171,7 +2177,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             }
             _ => {}
         }
-        visit::walk_expr(self, e);
+        visit::walk_expr(self, e)
     }
 
     fn visit_arm(&mut self, arm: &'a ast::Arm) {
@@ -2220,15 +2226,27 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
         }
 
-        visit::walk_fn(self, fn_kind, fn_decl, span);
+        visit::walk_fn(self, fn_kind, fn_decl, span)
     }
 
     fn visit_generic_param(&mut self, param: &'a GenericParam) {
-        if let GenericParamKind::Const { .. } = param.kind {
-            gate_feature_post!(&self, const_generics, param.ident.span,
-                "const generics are unstable");
+        match param.kind {
+            GenericParamKind::Const { .. } =>
+                gate_feature_post!(&self, const_generics, param.ident.span,
+                    "const generics are unstable"),
+            _ => {}
+        }
+        visit::walk_generic_param(self, param)
+    }
+
+    fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
+        match constraint.kind {
+            AssocTyConstraintKind::Bound { .. } =>
+                gate_feature_post!(&self, associated_type_bounds, constraint.span,
+                    "associated type bounds are unstable"),
+            _ => {}
         }
-        visit::walk_generic_param(self, param);
+        visit::walk_assoc_ty_constraint(self, constraint)
     }
 
     fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
@@ -2266,7 +2284,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             }
             _ => {}
         }
-        visit::walk_trait_item(self, ti);
+        visit::walk_trait_item(self, ti)
     }
 
     fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
@@ -2298,7 +2316,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             }
             _ => {}
         }
-        visit::walk_impl_item(self, ii);
+        visit::walk_impl_item(self, ii)
     }
 
     fn visit_vis(&mut self, vis: &'a ast::Visibility) {
@@ -2306,7 +2324,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             gate_feature_post!(&self, crate_visibility_modifier, vis.span,
                                "`crate` visibility modifier is experimental");
         }
-        visit::walk_vis(self, vis);
+        visit::walk_vis(self, vis)
     }
 }
 
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 75751309899..fb1a7a680ba 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -163,8 +163,8 @@ pub trait MutVisitor: Sized {
         noop_visit_lifetime(l, self);
     }
 
-    fn visit_ty_binding(&mut self, t: &mut TypeBinding) {
-        noop_visit_ty_binding(t, self);
+    fn visit_ty_constraint(&mut self, t: &mut AssocTyConstraint) {
+        noop_visit_ty_constraint(t, self);
     }
 
     fn visit_mod(&mut self, m: &mut Mod) {
@@ -400,11 +400,20 @@ pub fn noop_visit_guard<T: MutVisitor>(g: &mut Guard, vis: &mut T) {
     }
 }
 
-pub fn noop_visit_ty_binding<T: MutVisitor>(TypeBinding { id, ident, ty, span }: &mut TypeBinding,
-                                            vis: &mut T) {
+pub fn noop_visit_ty_constraint<T: MutVisitor>(
+    AssocTyConstraint { id, ident, kind, span }: &mut AssocTyConstraint,
+    vis: &mut T
+) {
     vis.visit_id(id);
     vis.visit_ident(ident);
-    vis.visit_ty(ty);
+    match kind {
+        AssocTyConstraintKind::Equality { ref mut ty } => {
+            vis.visit_ty(ty);
+        }
+        AssocTyConstraintKind::Bound { ref mut bounds } => {
+            visit_bounds(bounds, vis);
+        }
+    }
     vis.visit_span(span);
 }
 
@@ -499,9 +508,9 @@ pub fn noop_visit_generic_arg<T: MutVisitor>(arg: &mut GenericArg, vis: &mut T)
 
 pub fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>(data: &mut AngleBracketedArgs,
                                                                 vis: &mut T) {
-    let AngleBracketedArgs { args, bindings, span } = data;
+    let AngleBracketedArgs { args, constraints, span } = data;
     visit_vec(args, |arg| vis.visit_generic_arg(arg));
-    visit_vec(bindings, |binding| vis.visit_ty_binding(binding));
+    visit_vec(constraints, |constraint| vis.visit_ty_constraint(constraint));
     vis.visit_span(span);
 }
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 39fcd29e1b0..790013f6eb1 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -27,7 +27,7 @@ use crate::ast::{VariantData, StructField};
 use crate::ast::StrStyle;
 use crate::ast::SelfKind;
 use crate::ast::{TraitItem, TraitRef, TraitObjectSyntax};
-use crate::ast::{Ty, TyKind, TypeBinding, GenericBounds};
+use crate::ast::{Ty, TyKind, AssocTyConstraint, AssocTyConstraintKind, GenericBounds};
 use crate::ast::{Visibility, VisibilityKind, WhereClause, CrateSugar};
 use crate::ast::{UseTree, UseTreeKind};
 use crate::ast::{BinOpKind, UnOp};
@@ -191,24 +191,24 @@ enum PrevTokenKind {
     Other,
 }
 
-/* ident is handled by common.rs */
+// NOTE: `Ident`s are handled by `common.rs`.
 
 #[derive(Clone)]
 pub struct Parser<'a> {
     pub sess: &'a ParseSess,
-    /// the current token:
+    /// The current token.
     pub token: token::Token,
-    /// the span of the current token:
+    /// The span of the current token.
     pub span: Span,
-    /// the span of the previous token:
     meta_var_span: Option<Span>,
+    /// The span of the previous token.
     pub prev_span: Span,
-    /// the previous token kind
+    /// The kind of the previous troken.
     prev_token_kind: PrevTokenKind,
     restrictions: Restrictions,
-    /// Used to determine the path to externally loaded source files
+    /// Used to determine the path to externally loaded source files.
     crate directory: Directory<'a>,
-    /// Whether to parse sub-modules in other files.
+    /// `true` to parse sub-modules in other files.
     pub recurse_into_file_modules: bool,
     /// Name of the root module this parser originated from. If `None`, then the
     /// name is not known. This does not change while the parser is descending
@@ -217,7 +217,7 @@ pub struct Parser<'a> {
     crate expected_tokens: Vec<TokenType>,
     crate token_cursor: TokenCursor,
     desugar_doc_comments: bool,
-    /// Whether we should configure out of line modules as we parse.
+    /// `true` we should configure out of line modules as we parse.
     pub cfg_mods: bool,
     /// This field is used to keep track of how many left angle brackets we have seen. This is
     /// required in order to detect extra leading left angle brackets (`<` characters) and error
@@ -1791,11 +1791,11 @@ impl<'a> Parser<'a> {
             let lo = self.span;
             let args = if self.eat_lt() {
                 // `<'a, T, A = U>`
-                let (args, bindings) =
+                let (args, constraints) =
                     self.parse_generic_args_with_leaning_angle_bracket_recovery(style, lo)?;
                 self.expect_gt()?;
                 let span = lo.to(self.prev_span);
-                AngleBracketedArgs { args, bindings, span }.into()
+                AngleBracketedArgs { args, constraints, span }.into()
             } else {
                 // `(T, U) -> R`
                 self.bump(); // `(`
@@ -2680,8 +2680,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    // parse a stream of tokens into a list of TokenTree's,
-    // up to EOF.
+    /// Parses a stream of tokens into a list of `TokenTree`s, up to EOF.
     pub fn parse_all_token_trees(&mut self) -> PResult<'a, Vec<TokenTree>> {
         let mut tts = Vec::new();
         while self.token != token::Eof {
@@ -5077,7 +5076,7 @@ impl<'a> Parser<'a> {
         &mut self,
         style: PathStyle,
         lo: Span,
-    ) -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> {
+    ) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> {
         // We need to detect whether there are extra leading left angle brackets and produce an
         // appropriate error and suggestion. This cannot be implemented by looking ahead at
         // upcoming tokens for a matching `>` character - if there are unmatched `<` tokens
@@ -5212,11 +5211,11 @@ impl<'a> Parser<'a> {
 
     /// Parses (possibly empty) list of lifetime and type arguments and associated type bindings,
     /// possibly including trailing comma.
-    fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> {
+    fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> {
         let mut args = Vec::new();
-        let mut bindings = Vec::new();
-        let mut misplaced_assoc_ty_bindings: Vec<Span> = Vec::new();
-        let mut assoc_ty_bindings: Vec<Span> = Vec::new();
+        let mut constraints = Vec::new();
+        let mut misplaced_assoc_ty_constraints: Vec<Span> = Vec::new();
+        let mut assoc_ty_constraints: Vec<Span> = Vec::new();
 
         let args_lo = self.span;
 
@@ -5224,21 +5223,31 @@ impl<'a> Parser<'a> {
             if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
                 // Parse lifetime argument.
                 args.push(GenericArg::Lifetime(self.expect_lifetime()));
-                misplaced_assoc_ty_bindings.append(&mut assoc_ty_bindings);
-            } else if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) {
-                // Parse associated type binding.
+                misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
+            } else if self.check_ident() && self.look_ahead(1,
+                    |t| t == &token::Eq || t == &token::Colon) {
+                // Parse associated type constraint.
                 let lo = self.span;
                 let ident = self.parse_ident()?;
-                self.bump();
-                let ty = self.parse_ty()?;
+                let kind = if self.eat(&token::Eq) {
+                    AssocTyConstraintKind::Equality {
+                        ty: self.parse_ty()?,
+                    }
+                } else if self.eat(&token::Colon) {
+                    AssocTyConstraintKind::Bound {
+                        bounds: self.parse_generic_bounds(Some(self.prev_span))?,
+                    }
+                } else {
+                    unreachable!();
+                };
                 let span = lo.to(self.prev_span);
-                bindings.push(TypeBinding {
+                constraints.push(AssocTyConstraint {
                     id: ast::DUMMY_NODE_ID,
                     ident,
-                    ty,
+                    kind,
                     span,
                 });
-                assoc_ty_bindings.push(span);
+                assoc_ty_constraints.push(span);
             } else if self.check_const_arg() {
                 // Parse const argument.
                 let expr = if let token::OpenDelim(token::Brace) = self.token {
@@ -5262,11 +5271,11 @@ impl<'a> Parser<'a> {
                     value: expr,
                 };
                 args.push(GenericArg::Const(value));
-                misplaced_assoc_ty_bindings.append(&mut assoc_ty_bindings);
+                misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
             } else if self.check_type() {
                 // Parse type argument.
                 args.push(GenericArg::Type(self.parse_ty()?));
-                misplaced_assoc_ty_bindings.append(&mut assoc_ty_bindings);
+                misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
             } else {
                 break
             }
@@ -5279,12 +5288,12 @@ impl<'a> Parser<'a> {
         // FIXME: we would like to report this in ast_validation instead, but we currently do not
         // preserve ordering of generic parameters with respect to associated type binding, so we
         // lose that information after parsing.
-        if misplaced_assoc_ty_bindings.len() > 0 {
+        if misplaced_assoc_ty_constraints.len() > 0 {
             let mut err = self.struct_span_err(
                 args_lo.to(self.prev_span),
                 "associated type bindings must be declared after generic parameters",
             );
-            for span in misplaced_assoc_ty_bindings {
+            for span in misplaced_assoc_ty_constraints {
                 err.span_label(
                     span,
                     "this associated type binding should be moved after the generic parameters",
@@ -5293,7 +5302,7 @@ impl<'a> Parser<'a> {
             err.emit();
         }
 
-        Ok((args, bindings))
+        Ok((args, constraints))
     }
 
     /// Parses an optional where-clause and places it in `generics`.
@@ -5344,9 +5353,10 @@ impl<'a> Parser<'a> {
                 // Parse optional `for<'a, 'b>`.
                 // This `for` is parsed greedily and applies to the whole predicate,
                 // the bounded type can have its own `for` applying only to it.
-                // Example 1: for<'a> Trait1<'a>: Trait2<'a /*ok*/>
-                // Example 2: (for<'a> Trait1<'a>): Trait2<'a /*not ok*/>
-                // Example 3: for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /*ok*/, 'b /*not ok*/>
+                // Examples:
+                // * `for<'a> Trait1<'a>: Trait2<'a /* ok */>`
+                // * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>`
+                // * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>`
                 let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
 
                 // Parse type with mandatory colon and (possibly empty) bounds,
@@ -5478,17 +5488,17 @@ impl<'a> Parser<'a> {
             this.look_ahead(n + 1, |t| t != &token::ModSep)
         };
 
-        // Parse optional self parameter of a method.
-        // Only a limited set of initial token sequences is considered self parameters, anything
+        // Parse optional `self` parameter of a method.
+        // Only a limited set of initial token sequences is considered `self` parameters; anything
         // else is parsed as a normal function parameter list, so some lookahead is required.
         let eself_lo = self.span;
         let (eself, eself_ident, eself_hi) = match self.token {
             token::BinOp(token::And) => {
-                // &self
-                // &mut self
-                // &'lt self
-                // &'lt mut self
-                // &not_self
+                // `&self`
+                // `&mut self`
+                // `&'lt self`
+                // `&'lt mut self`
+                // `&not_self`
                 (if isolated_self(self, 1) {
                     self.bump();
                     SelfKind::Region(None, Mutability::Immutable)
@@ -5514,10 +5524,10 @@ impl<'a> Parser<'a> {
                 }, expect_ident(self), self.prev_span)
             }
             token::BinOp(token::Star) => {
-                // *self
-                // *const self
-                // *mut self
-                // *not_self
+                // `*self`
+                // `*const self`
+                // `*mut self`
+                // `*not_self`
                 // Emit special error for `self` cases.
                 let msg = "cannot pass `self` by raw pointer";
                 (if isolated_self(self, 1) {
@@ -5540,8 +5550,8 @@ impl<'a> Parser<'a> {
             }
             token::Ident(..) => {
                 if isolated_self(self, 0) {
-                    // self
-                    // self: TYPE
+                    // `self`
+                    // `self: TYPE`
                     let eself_ident = expect_ident(self);
                     let eself_hi = self.prev_span;
                     (if self.eat(&token::Colon) {
@@ -5552,8 +5562,8 @@ impl<'a> Parser<'a> {
                     }, eself_ident, eself_hi)
                 } else if self.token.is_keyword(kw::Mut) &&
                           isolated_self(self, 1) {
-                    // mut self
-                    // mut self: TYPE
+                    // `mut self`
+                    // `mut self: TYPE`
                     self.bump();
                     let eself_ident = expect_ident(self);
                     let eself_hi = self.prev_span;
@@ -5580,7 +5590,7 @@ impl<'a> Parser<'a> {
     {
         self.expect(&token::OpenDelim(token::Paren))?;
 
-        // Parse optional self argument
+        // Parse optional self argument.
         let self_arg = self.parse_self_arg()?;
 
         // Parse the rest of the function parameter list.
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index b81dc53ef68..57c01e9e3ef 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1715,7 +1715,7 @@ impl<'a> State<'a> {
         match els {
             Some(_else) => {
                 match _else.node {
-                    // "another else-if"
+                    // Another `else if` block.
                     ast::ExprKind::If(ref i, ref then, ref e) => {
                         self.cbox(INDENT_UNIT - 1)?;
                         self.ibox(0)?;
@@ -1725,7 +1725,7 @@ impl<'a> State<'a> {
                         self.print_block(then)?;
                         self.print_else(e.as_ref().map(|e| &**e))
                     }
-                    // "another else-if-let"
+                    // Another `else if let` block.
                     ast::ExprKind::IfLet(ref pats, ref expr, ref then, ref e) => {
                         self.cbox(INDENT_UNIT - 1)?;
                         self.ibox(0)?;
@@ -1738,14 +1738,14 @@ impl<'a> State<'a> {
                         self.print_block(then)?;
                         self.print_else(e.as_ref().map(|e| &**e))
                     }
-                    // "final else"
+                    // Final `else` block.
                     ast::ExprKind::Block(ref b, _) => {
                         self.cbox(INDENT_UNIT - 1)?;
                         self.ibox(0)?;
                         self.s.word(" else ")?;
                         self.print_block(b)
                     }
-                    // BLEAH, constraints would be great here
+                    // Constraints would be great here!
                     _ => {
                         panic!("print_if saw if with weird alternative");
                     }
@@ -2450,14 +2450,21 @@ impl<'a> State<'a> {
 
                 let mut comma = data.args.len() != 0;
 
-                for binding in data.bindings.iter() {
+                for constraint in data.constraints.iter() {
                     if comma {
                         self.word_space(",")?
                     }
-                    self.print_ident(binding.ident)?;
+                    self.print_ident(constraint.ident)?;
                     self.s.space()?;
-                    self.word_space("=")?;
-                    self.print_type(&binding.ty)?;
+                    match constraint.kind {
+                        ast::AssocTyConstraintKind::Equality { ref ty } => {
+                            self.word_space("=")?;
+                            self.print_type(ty)?;
+                        }
+                        ast::AssocTyConstraintKind::Bound { ref bounds } => {
+                            self.print_type_bounds(":", &*bounds)?;
+                        }
+                    }
                     comma = true;
                 }
 
diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs
index 9afcb7c4621..d577243fb3d 100644
--- a/src/libsyntax/ptr.rs
+++ b/src/libsyntax/ptr.rs
@@ -57,7 +57,8 @@ impl<T: 'static> P<T> {
     {
         f(*self.ptr)
     }
-    /// Equivalent to and_then(|x| x)
+
+    /// Equivalent to `and_then(|x| x)`.
     pub fn into_inner(self) -> T {
         *self.ptr
     }
diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs
index 521edac8f5f..f17eb3b3943 100644
--- a/src/libsyntax/util/node_count.rs
+++ b/src/libsyntax/util/node_count.rs
@@ -131,9 +131,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
         self.count += 1;
         walk_generic_args(self, path_span, generic_args)
     }
-    fn visit_assoc_type_binding(&mut self, type_binding: &TypeBinding) {
+    fn visit_assoc_ty_constraint(&mut self, constraint: &AssocTyConstraint) {
         self.count += 1;
-        walk_assoc_type_binding(self, type_binding)
+        walk_assoc_ty_constraint(self, constraint)
     }
     fn visit_attribute(&mut self, _attr: &Attribute) {
         self.count += 1;
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index eb516b5c7c6..334709b1521 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -139,8 +139,8 @@ pub trait Visitor<'ast>: Sized {
             GenericArg::Const(ct) => self.visit_anon_const(ct),
         }
     }
-    fn visit_assoc_type_binding(&mut self, type_binding: &'ast TypeBinding) {
-        walk_assoc_type_binding(self, type_binding)
+    fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) {
+        walk_assoc_ty_constraint(self, constraint)
     }
     fn visit_attribute(&mut self, attr: &'ast Attribute) {
         walk_attribute(self, attr)
@@ -404,7 +404,7 @@ pub fn walk_generic_args<'a, V>(visitor: &mut V,
     match *generic_args {
         GenericArgs::AngleBracketed(ref data) => {
             walk_list!(visitor, visit_generic_arg, &data.args);
-            walk_list!(visitor, visit_assoc_type_binding, &data.bindings);
+            walk_list!(visitor, visit_assoc_ty_constraint, &data.constraints);
         }
         GenericArgs::Parenthesized(ref data) => {
             walk_list!(visitor, visit_ty, &data.inputs);
@@ -413,10 +413,17 @@ pub fn walk_generic_args<'a, V>(visitor: &mut V,
     }
 }
 
-pub fn walk_assoc_type_binding<'a, V: Visitor<'a>>(visitor: &mut V,
-                                                   type_binding: &'a TypeBinding) {
-    visitor.visit_ident(type_binding.ident);
-    visitor.visit_ty(&type_binding.ty);
+pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(visitor: &mut V,
+                                                    constraint: &'a AssocTyConstraint) {
+    visitor.visit_ident(constraint.ident);
+    match constraint.kind {
+        AssocTyConstraintKind::Equality { ref ty } => {
+            visitor.visit_ty(ty);
+        }
+        AssocTyConstraintKind::Bound { ref bounds } => {
+            walk_list!(visitor, visit_param_bound, bounds);
+        }
+    }
 }
 
 pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
@@ -499,7 +506,7 @@ pub fn walk_generic_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Generi
     walk_list!(visitor, visit_attribute, param.attrs.iter());
     walk_list!(visitor, visit_param_bound, &param.bounds);
     match param.kind {
-        GenericParamKind::Lifetime => {}
+        GenericParamKind::Lifetime => (),
         GenericParamKind::Type { ref default } => walk_list!(visitor, visit_ty, default),
         GenericParamKind::Const { ref ty, .. } => visitor.visit_ty(ty),
     }