about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2014-11-07 06:53:45 -0500
committerNiko Matsakis <niko@alum.mit.edu>2014-11-07 15:51:30 -0500
commit244231720d29db856c5a28c0dda6c2efd7c9219a (patch)
tree41648e7c6c16102a7a602be441b4f1cdad8e7411
parentc18a1327e3ccf02ae9f755ca280d53177eeb298d (diff)
Update parser with `for` syntax
-rw-r--r--src/librustc/lint/builtin.rs4
-rw-r--r--src/librustc/middle/privacy.rs4
-rw-r--r--src/librustc/middle/resolve.rs30
-rw-r--r--src/librustc/middle/resolve_lifetime.rs161
-rw-r--r--src/librustc/middle/save/mod.rs3
-rw-r--r--src/librustc/middle/ty.rs3
-rw-r--r--src/librustc/middle/typeck/astconv.rs88
-rw-r--r--src/librustc/middle/typeck/collect.rs98
-rw-r--r--src/librustc/middle/typeck/infer/combine.rs1
-rw-r--r--src/librustc/middle/typeck/infer/error_reporting.rs13
-rw-r--r--src/librustdoc/clean/mod.rs9
-rw-r--r--src/libsyntax/ast.rs20
-rw-r--r--src/libsyntax/ast_map/mod.rs2
-rw-r--r--src/libsyntax/ext/build.rs15
-rw-r--r--src/libsyntax/ext/deriving/generic/ty.rs4
-rw-r--r--src/libsyntax/fold.rs24
-rw-r--r--src/libsyntax/parse/parser.rs310
-rw-r--r--src/libsyntax/print/pprust.rs31
-rw-r--r--src/libsyntax/visit.rs29
-rw-r--r--src/test/compile-fail/issue-10291.rs2
-rw-r--r--src/test/compile-fail/regions-fn-subtyping-return-static.rs4
-rw-r--r--src/test/compile-fail/regions-fn-subtyping.rs24
-rw-r--r--src/test/compile-fail/regions-name-undeclared.rs12
-rw-r--r--src/test/compile-fail/regions-nested-fns-2.rs2
-rw-r--r--src/test/compile-fail/regions-nested-fns.rs4
-rw-r--r--src/test/compile-fail/regions-ret-borrowed-1.rs2
-rw-r--r--src/test/run-pass/hrtb-parse.rs48
-rw-r--r--src/test/run-pass/nullable-pointer-ffi-compat.rs2
28 files changed, 544 insertions, 405 deletions
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 2858a830081..6f1287014d7 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -1690,8 +1690,8 @@ impl LintPass for Stability {
                 for t in supertraits.iter() {
                     match *t {
                         ast::TraitTyParamBound(ref t) => {
-                            let id = ty::trait_ref_to_def_id(cx.tcx, t);
-                            self.lint(cx, id, t.path.span);
+                            let id = ty::trait_ref_to_def_id(cx.tcx, &t.trait_ref);
+                            self.lint(cx, id, t.trait_ref.path.span);
                         }
                         _ => (/* pass */)
                     }
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index 21b94babcb6..eddd616e616 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -1291,7 +1291,7 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> {
         match *ty_param_bound {
             ast::TraitTyParamBound(ref trait_ref) => {
                 if !self.tcx.sess.features.borrow().visible_private_types &&
-                        self.path_is_private_type(trait_ref.ref_id) {
+                        self.path_is_private_type(trait_ref.trait_ref.ref_id) {
                     self.tcx.sess.span_err(span,
                                            "private type in exported type \
                                             parameter bound");
@@ -1432,7 +1432,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
                             //
                             // Those in 2. are warned via walk_generics and this
                             // call here.
-                            visit::walk_trait_ref_helper(self, tr)
+                            self.visit_trait_ref(tr)
                         }
                     }
                 } else if trait_ref.is_none() && self_is_public_path {
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index a1a8cccf55a..62d1e13d41f 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -33,12 +33,12 @@ use syntax::ast::{ItemTrait, ItemTy, LOCAL_CRATE, Local, ItemConst};
 use syntax::ast::{MethodImplItem, Mod, Name, NamedField, NodeId};
 use syntax::ast::{Pat, PatEnum, PatIdent, PatLit};
 use syntax::ast::{PatRange, PatStruct, Path, PathListIdent, PathListMod};
-use syntax::ast::{PrimTy, Public, SelfExplicit, SelfStatic};
+use syntax::ast::{PolyTraitRef, PrimTy, Public, SelfExplicit, SelfStatic};
 use syntax::ast::{RegionTyParamBound, StmtDecl, StructField};
 use syntax::ast::{StructVariantKind, TraitRef, TraitTyParamBound};
 use syntax::ast::{TupleVariantKind, Ty, TyBool, TyChar, TyClosure, TyF32};
 use syntax::ast::{TyF64, TyFloat, TyI, TyI8, TyI16, TyI32, TyI64, TyInt};
-use syntax::ast::{TyParam, TyParamBound, TyPath, TyPtr, TyProc, TyQPath};
+use syntax::ast::{TyParam, TyParamBound, TyPath, TyPtr, TyPolyTraitRef, TyProc, TyQPath};
 use syntax::ast::{TyRptr, TyStr, TyU, TyU8, TyU16, TyU32, TyU64, TyUint};
 use syntax::ast::{TypeImplItem, UnnamedField};
 use syntax::ast::{Variant, ViewItem, ViewItemExternCrate};
@@ -607,6 +607,7 @@ enum TraitReferenceType {
     TraitImplementation,             // impl SomeTrait for T { ... }
     TraitDerivation,                 // trait T : SomeTrait { ... }
     TraitBoundingTypeParameter,      // fn f<T:SomeTrait>() { ... }
+    TraitObject,                     // Box<for<'a> SomeTrait>
 }
 
 impl NameBindings {
@@ -4244,11 +4245,11 @@ impl<'a> Resolver<'a> {
                     this.resolve_type_parameter_bounds(item.id, bounds,
                                                        TraitDerivation);
 
-                    match unbound {
-                        &Some(ast::TraitTyParamBound(ref tpb)) => {
+                    match *unbound {
+                        Some(ref tpb) => {
                             this.resolve_trait_reference(item.id, tpb, TraitDerivation);
                         }
-                        _ => {}
+                        None => {}
                     }
 
                     for trait_item in (*trait_items).iter() {
@@ -4495,7 +4496,7 @@ impl<'a> Resolver<'a> {
         }
         match &type_parameter.unbound {
             &Some(ref unbound) =>
-                self.resolve_type_parameter_bound(
+                self.resolve_trait_reference(
                     type_parameter.id, unbound, TraitBoundingTypeParameter),
             &None => {}
         }
@@ -4521,12 +4522,19 @@ impl<'a> Resolver<'a> {
                                     reference_type: TraitReferenceType) {
         match *type_parameter_bound {
             TraitTyParamBound(ref tref) => {
-                self.resolve_trait_reference(id, tref, reference_type)
+                self.resolve_poly_trait_reference(id, tref, reference_type)
             }
             RegionTyParamBound(..) => {}
         }
     }
 
+    fn resolve_poly_trait_reference(&mut self,
+                                    id: NodeId,
+                                    poly_trait_reference: &PolyTraitRef,
+                                    reference_type: TraitReferenceType) {
+        self.resolve_trait_reference(id, &poly_trait_reference.trait_ref, reference_type)
+    }
+
     fn resolve_trait_reference(&mut self,
                                id: NodeId,
                                trait_reference: &TraitRef,
@@ -4538,6 +4546,7 @@ impl<'a> Resolver<'a> {
                     TraitBoundingTypeParameter => "bound type parameter with",
                     TraitImplementation        => "implement",
                     TraitDerivation            => "derive",
+                    TraitObject                => "reference",
                 };
 
                 let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str);
@@ -5044,6 +5053,13 @@ impl<'a> Resolver<'a> {
                 visit::walk_ty(self, ty);
             }
 
+            TyPolyTraitRef(ref poly_trait_ref) => {
+                self.resolve_poly_trait_reference(
+                    ty.id,
+                    &**poly_trait_ref,
+                    TraitObject);
+                visit::walk_ty(self, ty);
+            }
             _ => {
                 // Just resolve embedded types.
                 visit::walk_ty(self, ty);
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 8246970c24a..8ac52b891b9 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -19,6 +19,7 @@
 
 use driver::session::Session;
 use middle::subst;
+use std::fmt;
 use syntax::ast;
 use syntax::codemap::Span;
 use syntax::owned_slice::OwnedSlice;
@@ -46,18 +47,12 @@ pub enum DefRegion {
 // that it corresponds to
 pub type NamedRegionMap = NodeMap<DefRegion>;
 
-// Returns an instance of some type that implements std::fmt::Show
-fn lifetime_show(lt_name: &ast::Name) -> token::InternedString {
-    token::get_name(*lt_name)
-}
-
 struct LifetimeContext<'a> {
     sess: &'a Session,
     named_region_map: &'a mut NamedRegionMap,
     scope: Scope<'a>
 }
 
-#[deriving(Show)]
 enum ScopeChain<'a> {
     /// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound
     /// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc.
@@ -88,42 +83,32 @@ pub fn krate(sess: &Session, krate: &ast::Crate) -> NamedRegionMap {
 
 impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
     fn visit_item(&mut self, item: &ast::Item) {
-        let lifetimes = match item.node {
-            ast::ItemFn(..) | // fn lifetimes get added in visit_fn below
+        match item.node {
+            ast::ItemFn(..) => {
+                // Fn lifetimes get added in visit_fn below:
+                self.with(RootScope, |this| visit::walk_item(this, item));
+            }
             ast::ItemMod(..) |
             ast::ItemMac(..) |
             ast::ItemForeignMod(..) |
-            ast::ItemStatic(..) | ast::ItemConst(..) => {
-                self.with(|_, f| f(RootScope), |v| visit::walk_item(v, item));
-                return;
+            ast::ItemStatic(..) |
+            ast::ItemConst(..) => {
+                // These sorts of items have no lifetime parameters at all.
+                self.with(RootScope, |this| visit::walk_item(this, item));
             }
             ast::ItemTy(_, ref generics) |
             ast::ItemEnum(_, ref generics) |
             ast::ItemStruct(_, ref generics) |
-            ast::ItemTrait(ref generics, _, _, _) => {
-                self.with(|scope, f| {
-                    f(EarlyScope(subst::TypeSpace,
-                                 &generics.lifetimes,
-                                 scope))
-                }, |v| v.check_lifetime_defs(&generics.lifetimes));
-                &generics.lifetimes
-            }
+            ast::ItemTrait(ref generics, _, _, _) |
             ast::ItemImpl(ref generics, _, _, _) => {
-                self.with(|scope, f| {
-                    f(EarlyScope(subst::TypeSpace,
-                                 &generics.lifetimes,
-                                 scope))
-                }, |v| v.check_lifetime_defs(&generics.lifetimes));
-                &generics.lifetimes
+                // These kinds of items have only early bound lifetime parameters.
+                let lifetimes = &generics.lifetimes;
+                self.with(EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE), |this| {
+                    this.check_lifetime_defs(lifetimes);
+                    visit::walk_item(this, item);
+                });
             }
-        };
-
-        self.with(|_, f| f(EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE)), |v| {
-            debug!("entering scope {}", v.scope);
-            v.check_lifetime_defs(lifetimes);
-            visit::walk_item(v, item);
-            debug!("exiting scope {}", v.scope);
-        });
+        }
     }
 
     fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
@@ -131,7 +116,9 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
         match fk {
             visit::FkItemFn(_, generics, _, _) |
             visit::FkMethod(_, generics, _) => {
-                self.visit_fn_decl(n, generics, |v| visit::walk_fn(v, fk, fd, b, s))
+                self.visit_early_late(
+                    subst::FnSpace, n, generics,
+                    |this| visit::walk_fn(this, fk, fd, b, s))
             }
             visit::FkFnBlock(..) => {
                 visit::walk_fn(self, fk, fd, b, s)
@@ -146,22 +133,20 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
             _ => return visit::walk_ty(self, ty)
         };
 
-        self.with(|scope, f| f(LateScope(ty.id, lifetimes, scope)), |v| {
-            v.check_lifetime_defs(lifetimes);
-            debug!("pushing fn scope id={} due to type", ty.id);
-            visit::walk_ty(v, ty);
-            debug!("popping fn scope id={} due to type", ty.id);
+        self.with(LateScope(ty.id, lifetimes, self.scope), |this| {
+            this.check_lifetime_defs(lifetimes);
+            visit::walk_ty(this, ty);
         });
     }
 
     fn visit_ty_method(&mut self, m: &ast::TypeMethod) {
-        self.visit_fn_decl(m.id, &m.generics, |v| visit::walk_ty_method(v, m))
+        self.visit_early_late(
+            subst::FnSpace, m.id, &m.generics,
+            |this| visit::walk_ty_method(this, m))
     }
 
     fn visit_block(&mut self, b: &ast::Block) {
-        debug!("pushing block scope {}", b.id);
-        self.with(|scope, f| f(BlockScope(b.id, scope)), |v| visit::walk_block(v, b));
-        debug!("popping block scope {}", b.id);
+        self.with(BlockScope(b.id, self.scope), |this| visit::walk_block(this, b));
     }
 
     fn visit_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) {
@@ -188,13 +173,16 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
 }
 
 impl<'a> LifetimeContext<'a> {
-    fn with(&mut self, wrap_scope: |Scope, |ScopeChain||, f: |&mut LifetimeContext|) {
-        let LifetimeContext { sess, ref mut named_region_map, scope} = *self;
-        wrap_scope(scope, |scope1| f(&mut LifetimeContext {
+    fn with(&mut self, wrap_scope: ScopeChain, f: |&mut LifetimeContext|) {
+        let LifetimeContext {sess, ref mut named_region_map, ..} = *self;
+        let mut this = LifetimeContext {
             sess: sess,
             named_region_map: *named_region_map,
-            scope: &scope1
-        }))
+            scope: &wrap_scope
+        };
+        debug!("entering scope {}", this.scope);
+        f(&mut this);
+        debug!("exiting scope {}", this.scope);
     }
 
     fn visit_ty_param_bounds(&mut self,
@@ -202,7 +190,7 @@ impl<'a> LifetimeContext<'a> {
         for bound in bounds.iter() {
             match *bound {
                 ast::TraitTyParamBound(ref trait_ref) => {
-                    self.visit_trait_ref(trait_ref);
+                    self.visit_poly_trait_ref(trait_ref);
                 }
                 ast::RegionTyParamBound(ref lifetime) => {
                     self.visit_lifetime_ref(lifetime);
@@ -211,23 +199,27 @@ impl<'a> LifetimeContext<'a> {
         }
     }
 
-    fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
-        self.with(|scope, f| {
-            f(LateScope(trait_ref.ref_id, &trait_ref.lifetimes, scope))
-        }, |v| {
-            v.check_lifetime_defs(&trait_ref.lifetimes);
-            for lifetime in trait_ref.lifetimes.iter() {
-                v.visit_lifetime_decl(lifetime);
+    fn visit_poly_trait_ref(&mut self, trait_ref: &ast::PolyTraitRef) {
+        let ref_id = trait_ref.trait_ref.ref_id;
+        self.with(LateScope(ref_id, &trait_ref.bound_lifetimes, self.scope), |this| {
+            this.check_lifetime_defs(&trait_ref.bound_lifetimes);
+            for lifetime in trait_ref.bound_lifetimes.iter() {
+                this.visit_lifetime_decl(lifetime);
             }
-            v.visit_path(&trait_ref.path, trait_ref.ref_id);
+            this.visit_trait_ref(&trait_ref.trait_ref)
         })
     }
 
+    fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
+        self.visit_path(&trait_ref.path, trait_ref.ref_id);
+    }
+
     /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
-    fn visit_fn_decl(&mut self,
-                     n: ast::NodeId,
-                     generics: &ast::Generics,
-                     walk: |&mut LifetimeContext|) {
+    fn visit_early_late(&mut self,
+                        early_space: subst::ParamSpace,
+                        binder_id: ast::NodeId,
+                        generics: &ast::Generics,
+                        walk: |&mut LifetimeContext|) {
         /*!
          * Handles visiting fns and methods. These are a bit
          * complicated because we must distinguish early- vs late-bound
@@ -248,33 +240,25 @@ impl<'a> LifetimeContext<'a> {
          * numbered sequentially, starting from the lowest index that
          * is already in scope (for a fn item, that will be 0, but for
          * a method it might not be). Late bound lifetimes are
-         * resolved by name and associated with a binder id (`n`), so
+         * resolved by name and associated with a binder id (`binder_id`), so
          * the ordering is not important there.
          */
 
         let referenced_idents = early_bound_lifetime_names(generics);
-        debug!("pushing fn scope id={} due to fn item/method\
-               referenced_idents={}",
-               n,
-               referenced_idents.iter().map(lifetime_show).collect::<Vec<token::InternedString>>());
-        let lifetimes = &generics.lifetimes;
-        if referenced_idents.is_empty() {
-            self.with(|scope, f| f(LateScope(n, lifetimes, scope)), |v| {
-                v.check_lifetime_defs(lifetimes);
-                walk(v);
-            });
-        } else {
-            let (early, late) = lifetimes.clone().partition(
-                |l| referenced_idents.iter().any(|&i| i == l.lifetime.name));
-
-            self.with(|scope, f| f(EarlyScope(subst::FnSpace, &early, scope)), |v| {
-                v.with(|scope1, f| f(LateScope(n, &late, scope1)), |v| {
-                    v.check_lifetime_defs(lifetimes);
-                    walk(v);
-                });
+
+        debug!("visit_early_late: binder_id={} referenced_idents={}",
+               binder_id,
+               referenced_idents);
+
+        let (early, late) = generics.lifetimes.clone().partition(
+            |l| referenced_idents.iter().any(|&i| i == l.lifetime.name));
+
+        self.with(EarlyScope(early_space, &early, self.scope), |this| {
+            this.with(LateScope(binder_id, &late, this.scope), |this| {
+                this.check_lifetime_defs(&generics.lifetimes);
+                walk(this);
             });
-        }
-        debug!("popping fn scope id={} due to fn item/method", n);
+        });
     }
 
     fn resolve_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) {
@@ -525,3 +509,14 @@ fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec<ast::Name> {
         }
     }
 }
+
+impl<'a> fmt::Show for ScopeChain<'a> {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            EarlyScope(space, defs, _) => write!(fmt, "EarlyScope({}, {})", space, defs),
+            LateScope(id, defs, _) => write!(fmt, "LateScope({}, {})", id, defs),
+            BlockScope(id, _) => write!(fmt, "BlockScope({})", id),
+            RootScope => write!(fmt, "RootScope"),
+        }
+    }
+}
diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs
index b64a160ab1f..a2b80686d01 100644
--- a/src/librustc/middle/save/mod.rs
+++ b/src/librustc/middle/save/mod.rs
@@ -710,6 +710,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
                 }
             };
 
+            let trait_ref = &trait_ref.trait_ref;
             match self.lookup_type_ref(trait_ref.ref_id) {
                 Some(id) => {
                     let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
@@ -1068,7 +1069,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
             for bound in param.bounds.iter() {
                 match *bound {
                     ast::TraitTyParamBound(ref trait_ref) => {
-                        self.process_trait_ref(trait_ref, None);
+                        self.process_trait_ref(&trait_ref.trait_ref, None);
                     }
                     _ => {}
                 }
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 3e8a7bb842c..1a6e8eeb320 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -5546,7 +5546,8 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
             ty_param(_) |
             ty_infer(_) |
             ty_open(_) |
-            ty_err => {}
+            ty_err => {
+            }
         }
     });
 
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index 6430362f9cd..e27ff636a2a 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -51,8 +51,6 @@
 
 use middle::const_eval;
 use middle::def;
-use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem};
-use middle::lang_items::{FnOnceTraitLangItem};
 use middle::resolve_lifetime as rl;
 use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs};
 use middle::subst::{VecPerParamSpace};
@@ -398,6 +396,46 @@ fn ast_path_substs<'tcx,AC,RS>(
     }
 }
 
+pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC,
+                                         rscope: &RS,
+                                         ast_trait_ref: &ast::TraitRef,
+                                         self_ty: Option<ty::t>,
+                                         associated_type: Option<ty::t>)
+                                         -> Rc<ty::TraitRef>
+                                         where AC: AstConv<'tcx>,
+                                               RS: RegionScope
+{
+    /*!
+     * Instantiates the path for the given trait reference, assuming that
+     * it's bound to a valid trait type. Returns the def_id for the defining
+     * trait. Fails if the type is a type other than a trait type.
+     */
+
+    match lookup_def_tcx(this.tcx(),
+                         ast_trait_ref.path.span,
+                         ast_trait_ref.ref_id) {
+        def::DefTrait(trait_did) => {
+            let trait_ref =
+                Rc::new(ast_path_to_trait_ref(this,
+                                              rscope,
+                                              trait_did,
+                                              self_ty,
+                                              associated_type,
+                                              &ast_trait_ref.path,
+                                              ast_trait_ref.ref_id));
+
+            this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id,
+                                                      trait_ref.clone());
+            trait_ref
+        }
+        _ => {
+            this.tcx().sess.span_fatal(
+                ast_trait_ref.path.span,
+                format!("`{}` is not a trait", ast_trait_ref.path.user_string(this.tcx()))[]);
+        }
+    }
+}
+
 pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC,
                                          rscope: &RS,
                                          trait_def_id: ast::DefId,
@@ -620,41 +658,6 @@ enum PointerTy {
     Uniq
 }
 
-pub fn trait_ref_for_unboxed_function<'tcx, AC: AstConv<'tcx>,
-                                      RS:RegionScope>(
-                                      this: &AC,
-                                      rscope: &RS,
-                                      kind: ast::UnboxedClosureKind,
-                                      decl: &ast::FnDecl,
-                                      self_ty: Option<ty::t>)
-                                      -> ty::TraitRef {
-    let lang_item = match kind {
-        ast::FnUnboxedClosureKind => FnTraitLangItem,
-        ast::FnMutUnboxedClosureKind => FnMutTraitLangItem,
-        ast::FnOnceUnboxedClosureKind => FnOnceTraitLangItem,
-    };
-    let trait_did = this.tcx().lang_items.require(lang_item).unwrap();
-    let input_types = decl.inputs
-                          .iter()
-                          .map(|input| {
-                            ast_ty_to_ty(this, rscope, &*input.ty)
-                          }).collect::<Vec<_>>();
-    let input_tuple = ty::mk_tup_or_nil(this.tcx(), input_types);
-    let output_type = ast_ty_to_ty(this, rscope, &*decl.output);
-    let mut substs = Substs::new_type(vec!(input_tuple, output_type),
-                                      Vec::new());
-
-    match self_ty {
-        Some(s) => substs.types.push(SelfSpace, s),
-        None => ()
-    }
-
-    ty::TraitRef {
-        def_id: trait_did,
-        substs: substs,
-    }
-}
-
 // Handle `~`, `Box`, and `&` being able to mean strs and vecs.
 // If a_seq_ty is a str or a vec, make it a str/vec.
 // Also handle first-class trait types.
@@ -898,6 +901,16 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
 
                 ty::mk_closure(tcx, fn_decl)
             }
+            ast::TyPolyTraitRef(ref data) => {
+                // FIXME(#18639) this is just a placeholder for code to come
+                let principal = instantiate_trait_ref(this, rscope, &data.trait_ref, None, None);
+                let bounds = conv_existential_bounds(this,
+                                                     rscope,
+                                                     ast_ty.span,
+                                                     &[principal.clone()],
+                                                     &[]);
+                ty::mk_trait(tcx, (*principal).clone(), bounds)
+            }
             ast::TyPath(ref path, ref bounds, id) => {
                 let a_def = match tcx.def_map.borrow().get(&id) {
                     None => {
@@ -1536,6 +1549,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
     for &ast_bound in ast_bounds.iter() {
         match *ast_bound {
             ast::TraitTyParamBound(ref b) => {
+                let b = &b.trait_ref; // FIXME
                 match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
                     def::DefTrait(trait_did) => {
                         match trait_def_ids.get(&trait_did) {
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index d365c54c701..42411b598bf 100644
--- a/src/librustc/middle/typeck/collect.rs
+++ b/src/librustc/middle/typeck/collect.rs
@@ -61,7 +61,6 @@ use syntax::ast_util::{local_def, PostExpansionMethod};
 use syntax::codemap::Span;
 use syntax::parse::token::{special_idents};
 use syntax::parse::token;
-use syntax::print::pprust::{path_to_string};
 use syntax::ptr::P;
 use syntax::visit;
 
@@ -633,24 +632,33 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
                                  span: Span,
                                  generics: &ast::Generics,
                                  thing: &'static str) {
+    let mut warn = false;
+
     for ty_param in generics.ty_params.iter() {
-        let bounds = ty_param.bounds.iter();
-        let mut bounds = bounds.chain(ty_param.unbound.iter());
-        for bound in bounds {
+        for bound in ty_param.bounds.iter() {
             match *bound {
                 ast::TraitTyParamBound(..) => {
-                    // According to accepted RFC #XXX, we should
-                    // eventually accept these, but it will not be
-                    // part of this PR. Still, convert to warning to
-                    // make bootstrapping easier.
-                    span_warn!(ccx.tcx.sess, span, E0122,
-                               "trait bounds are not (yet) enforced \
-                                in {} definitions",
-                               thing);
+                    warn = true;
                 }
                 ast::RegionTyParamBound(..) => { }
             }
         }
+
+        match ty_param.unbound {
+            Some(_) => { warn = true; }
+            None => { }
+        }
+    }
+
+    if warn {
+        // According to accepted RFC #XXX, we should
+        // eventually accept these, but it will not be
+        // part of this PR. Still, convert to warning to
+        // make bootstrapping easier.
+        span_warn!(ccx.tcx.sess, span, E0122,
+                   "trait bounds are not (yet) enforced \
+                   in {} definitions",
+                   thing);
     }
 }
 
@@ -1147,7 +1155,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
                             parent_visibility);
 
             for trait_ref in opt_trait_ref.iter() {
-                instantiate_trait_ref(&icx, trait_ref, selfty, None);
+                astconv::instantiate_trait_ref(&icx, &ExplicitRscope, trait_ref, Some(selfty), None);
             }
         },
         ast::ItemTrait(_, _, _, ref trait_methods) => {
@@ -1315,47 +1323,6 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::ForeignItem) {
     ccx.tcx.tcache.borrow_mut().insert(local_def(i.id), pty);
 }
 
-pub fn instantiate_trait_ref<'tcx,AC>(this: &AC,
-                                      ast_trait_ref: &ast::TraitRef,
-                                      self_ty: ty::t,
-                                      associated_type: Option<ty::t>)
-                                      -> Rc<ty::TraitRef>
-                                      where AC: AstConv<'tcx> {
-    /*!
-     * Instantiates the path for the given trait reference, assuming that
-     * it's bound to a valid trait type. Returns the def_id for the defining
-     * trait. Fails if the type is a type other than a trait type.
-     */
-
-    // FIXME(#5121) -- distinguish early vs late lifetime params
-    let rscope = ExplicitRscope;
-
-    match lookup_def_tcx(this.tcx(),
-                         ast_trait_ref.path.span,
-                         ast_trait_ref.ref_id) {
-        def::DefTrait(trait_did) => {
-            let trait_ref =
-                Rc::new(astconv::ast_path_to_trait_ref(this,
-                                                       &rscope,
-                                                       trait_did,
-                                                       Some(self_ty),
-                                                       associated_type,
-                                                       &ast_trait_ref.path,
-                                                       ast_trait_ref.ref_id));
-
-            this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id,
-                                                      trait_ref.clone());
-            trait_ref
-        }
-        _ => {
-            this.tcx().sess.span_fatal(
-                ast_trait_ref.path.span,
-                format!("`{}` is not a trait",
-                        path_to_string(&ast_trait_ref.path)).as_slice());
-        }
-    }
-}
-
 fn get_trait_def(ccx: &CrateCtxt, trait_id: ast::DefId) -> Rc<ty::TraitDef> {
     if trait_id.krate != ast::LOCAL_CRATE {
         return ty::lookup_trait_def(ccx.tcx, trait_id)
@@ -1720,14 +1687,14 @@ fn ty_generics_for_fn_or_method<'tcx,AC>(
 
 // Add the Sized bound, unless the type parameter is marked as `Sized?`.
 fn add_unsized_bound<'tcx,AC>(this: &AC,
-                              unbound: &Option<ast::TyParamBound>,
+                              unbound: &Option<ast::TraitRef>,
                               bounds: &mut ty::BuiltinBounds,
                               desc: &str,
                               span: Span)
                               where AC: AstConv<'tcx> {
     let kind_id = this.tcx().lang_items.require(SizedTraitLangItem);
     match unbound {
-        &Some(ast::TraitTyParamBound(ref tpb)) => {
+        &Some(ref tpb) => {
             // FIXME(#8559) currently requires the unbound to be built-in.
             let trait_def_id = ty::trait_ref_to_def_id(this.tcx(), tpb);
             match kind_id {
@@ -1752,7 +1719,7 @@ fn add_unsized_bound<'tcx,AC>(this: &AC,
             ty::try_add_builtin_trait(this.tcx(), kind_id.unwrap(), bounds);
         }
         // No lang item for Sized, so we can't add it as a bound.
-        _ => {}
+        &None => {}
     }
 }
 
@@ -1870,11 +1837,11 @@ fn ty_generics<'tcx,AC>(this: &AC,
 
                 let trait_def_id =
                     match lookup_def_tcx(this.tcx(),
-                                         ast_trait_ref.path.span,
-                                         ast_trait_ref.ref_id) {
+                                         ast_trait_ref.trait_ref.path.span,
+                                         ast_trait_ref.trait_ref.ref_id) {
                         def::DefTrait(trait_def_id) => trait_def_id,
                         _ => {
-                            this.tcx().sess.span_bug(ast_trait_ref.path.span,
+                            this.tcx().sess.span_bug(ast_trait_ref.trait_ref.path.span,
                                                      "not a trait?!")
                         }
                     };
@@ -1972,7 +1939,7 @@ fn compute_bounds<'tcx,AC>(this: &AC,
                            name_of_bounded_thing: ast::Name,
                            param_ty: ty::ParamTy,
                            ast_bounds: &[ast::TyParamBound],
-                           unbound: &Option<ast::TyParamBound>,
+                           unbound: &Option<ast::TraitRef>,
                            span: Span,
                            where_clause: &ast::WhereClause)
                            -> ty::ParamBounds
@@ -2047,10 +2014,11 @@ fn conv_param_bounds<'tcx,AC>(this: &AC,
     let trait_bounds: Vec<Rc<ty::TraitRef>> =
         trait_bounds.into_iter()
         .map(|b| {
-            instantiate_trait_ref(this,
-                                  b,
-                                  param_ty.to_ty(this.tcx()),
-                                  Some(param_ty.to_ty(this.tcx())))
+            astconv::instantiate_trait_ref(this,
+                                           &ExplicitRscope,
+                                           b,
+                                           Some(param_ty.to_ty(this.tcx())),
+                                           Some(param_ty.to_ty(this.tcx())))
         })
         .collect();
     let region_bounds: Vec<ty::Region> =
diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs
index ab3ec4991c3..83d90274fd3 100644
--- a/src/librustc/middle/typeck/infer/combine.rs
+++ b/src/librustc/middle/typeck/infer/combine.rs
@@ -52,7 +52,6 @@ use middle::typeck::infer::type_variable::{RelationDir, EqTo,
 use middle::ty_fold::{TypeFoldable};
 use util::ppaux::Repr;
 
-
 use syntax::ast::{Onceness, FnStyle};
 use syntax::ast;
 use syntax::abi;
diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs
index 4ca62253467..80b4948f6fb 100644
--- a/src/librustc/middle/typeck/infer/error_reporting.rs
+++ b/src/librustc/middle/typeck/infer/error_reporting.rs
@@ -1102,7 +1102,8 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
                     // be passing down a map.
                     ast::RegionTyParamBound(lt)
                 }
-                &ast::TraitTyParamBound(ref tr) => {
+                &ast::TraitTyParamBound(ref poly_tr) => {
+                    let tr = &poly_tr.trait_ref;
                     let last_seg = tr.path.segments.last().unwrap();
                     let mut insert = Vec::new();
                     let lifetimes = last_seg.parameters.lifetimes();
@@ -1119,10 +1120,12 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
                         region_names: region_names
                     };
                     let new_path = self.rebuild_path(rebuild_info, lifetime);
-                    ast::TraitTyParamBound(ast::TraitRef {
-                        path: new_path,
-                        ref_id: tr.ref_id,
-                        lifetimes: tr.lifetimes.clone(),
+                    ast::TraitTyParamBound(ast::PolyTraitRef {
+                        bound_lifetimes: poly_tr.bound_lifetimes.clone(),
+                        trait_ref: ast::TraitRef {
+                            path: new_path,
+                            ref_id: tr.ref_id,
+                        }
                     })
                 }
             }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 4478c29f66a..38e0c4fe040 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -963,6 +963,12 @@ impl Clean<Type> for ast::TraitRef {
     }
 }
 
+impl Clean<Type> for ast::PolyTraitRef {
+    fn clean(&self, cx: &DocContext) -> Type {
+        self.trait_ref.clean(cx)
+    }
+}
+
 #[deriving(Clone, Encodable, Decodable)]
 pub enum TraitMethod {
     RequiredMethod(Item),
@@ -1306,7 +1312,8 @@ impl Clean<Type> for ty::t {
             }
             ty::ty_struct(did, ref substs) |
             ty::ty_enum(did, ref substs) |
-            ty::ty_trait(box ty::TyTrait { def_id: did, ref substs, .. }) => {
+            ty::ty_trait(box ty::TyTrait { principal: ty::TraitRef { def_id: did, ref substs },
+                                           .. }) => {
                 let fqn = csearch::get_item_path(cx.tcx(), did);
                 let fqn: Vec<String> = fqn.into_iter().map(|i| {
                     i.to_string()
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 20f7caac482..145978bb73f 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -307,7 +307,7 @@ pub const DUMMY_NODE_ID: NodeId = -1;
 /// detects Copy, Send and Sync.
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
 pub enum TyParamBound {
-    TraitTyParamBound(TraitRef),
+    TraitTyParamBound(PolyTraitRef),
     RegionTyParamBound(Lifetime)
 }
 
@@ -318,7 +318,7 @@ pub struct TyParam {
     pub ident: Ident,
     pub id: NodeId,
     pub bounds: TyParamBounds,
-    pub unbound: Option<TyParamBound>,
+    pub unbound: Option<TraitRef>,
     pub default: Option<P<Ty>>,
     pub span: Span
 }
@@ -1097,6 +1097,7 @@ pub enum Ty_ {
     TyBareFn(P<BareFnTy>),
     TyTup(Vec<P<Ty>> ),
     TyPath(Path, Option<TyParamBounds>, NodeId), // for #7264; see above
+    TyPolyTraitRef(P<PolyTraitRef>), // a type like `for<'a> Foo<&'a Bar>`
     /// A "qualified path", e.g. `<Vec<T> as SomeTrait>::SomeType`
     TyQPath(P<QPath>),
     /// No-op; kept solely so that we can pretty-print faithfully
@@ -1350,7 +1351,6 @@ pub struct Attribute_ {
     pub is_sugared_doc: bool,
 }
 
-
 /// TraitRef's appear in impls.
 /// resolve maps each TraitRef's ref_id to its defining trait; that's all
 /// that the ref_id is for. The impl_id maps to the "self type" of this impl.
@@ -1360,7 +1360,15 @@ pub struct Attribute_ {
 pub struct TraitRef {
     pub path: Path,
     pub ref_id: NodeId,
-    pub lifetimes: Vec<LifetimeDef>,
+}
+
+#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
+pub struct PolyTraitRef {
+    /// The `'a` in `<'a> Foo<&'a T>`
+    pub bound_lifetimes: Vec<LifetimeDef>,
+
+    /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
+    pub trait_ref: TraitRef
 }
 
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
@@ -1448,8 +1456,8 @@ pub enum Item_ {
     ItemStruct(P<StructDef>, Generics),
     /// Represents a Trait Declaration
     ItemTrait(Generics,
-              Option<TyParamBound>, // (optional) default bound not required for Self.
-                                    // Currently, only Sized makes sense here.
+              Option<TraitRef>, // (optional) default bound not required for Self.
+                                // Currently, only Sized makes sense here.
               TyParamBounds,
               Vec<TraitItem>),
     ItemImpl(Generics,
diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs
index 3adb062864e..d65be4c45e8 100644
--- a/src/libsyntax/ast_map/mod.rs
+++ b/src/libsyntax/ast_map/mod.rs
@@ -770,7 +770,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
                 for b in bounds.iter() {
                     match *b {
                         TraitTyParamBound(ref t) => {
-                            self.insert(t.ref_id, NodeItem(i));
+                            self.insert(t.trait_ref.ref_id, NodeItem(i));
                         }
                         _ => {}
                     }
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 5921d630b89..862cbf3d7ca 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -68,10 +68,11 @@ pub trait AstBuilder {
                span: Span,
                id: ast::Ident,
                bounds: OwnedSlice<ast::TyParamBound>,
-               unbound: Option<ast::TyParamBound>,
+               unbound: Option<ast::TraitRef>,
                default: Option<P<ast::Ty>>) -> ast::TyParam;
 
     fn trait_ref(&self, path: ast::Path) -> ast::TraitRef;
+    fn poly_trait_ref(&self, path: ast::Path) -> ast::PolyTraitRef;
     fn typarambound(&self, path: ast::Path) -> ast::TyParamBound;
     fn lifetime(&self, span: Span, ident: ast::Name) -> ast::Lifetime;
     fn lifetime_def(&self,
@@ -417,7 +418,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
                span: Span,
                id: ast::Ident,
                bounds: OwnedSlice<ast::TyParamBound>,
-               unbound: Option<ast::TyParamBound>,
+               unbound: Option<ast::TraitRef>,
                default: Option<P<ast::Ty>>) -> ast::TyParam {
         ast::TyParam {
             ident: id,
@@ -445,12 +446,18 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         ast::TraitRef {
             path: path,
             ref_id: ast::DUMMY_NODE_ID,
-            lifetimes: Vec::new(),
+        }
+    }
+
+    fn poly_trait_ref(&self, path: ast::Path) -> ast::PolyTraitRef {
+        ast::PolyTraitRef {
+            bound_lifetimes: Vec::new(),
+            trait_ref: self.trait_ref(path)
         }
     }
 
     fn typarambound(&self, path: ast::Path) -> ast::TyParamBound {
-        ast::TraitTyParamBound(self.trait_ref(path))
+        ast::TraitTyParamBound(self.poly_trait_ref(path))
     }
 
     fn lifetime(&self, span: Span, name: ast::Name) -> ast::Lifetime {
diff --git a/src/libsyntax/ext/deriving/generic/ty.rs b/src/libsyntax/ext/deriving/generic/ty.rs
index a90618a30b6..1ec1e3b1224 100644
--- a/src/libsyntax/ext/deriving/generic/ty.rs
+++ b/src/libsyntax/ext/deriving/generic/ty.rs
@@ -194,7 +194,7 @@ impl<'a> Ty<'a> {
 
 
 fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str,
-               bounds: &[Path], unbound: Option<ast::TyParamBound>,
+               bounds: &[Path], unbound: Option<ast::TraitRef>,
                self_ident: Ident, self_generics: &Generics) -> ast::TyParam {
     let bounds =
         bounds.iter().map(|b| {
@@ -220,7 +220,7 @@ fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>)
 #[deriving(Clone)]
 pub struct LifetimeBounds<'a> {
     pub lifetimes: Vec<(&'a str, Vec<&'a str>)>,
-    pub bounds: Vec<(&'a str, Option<ast::TyParamBound>, Vec<Path<'a>>)>,
+    pub bounds: Vec<(&'a str, Option<ast::TraitRef>, Vec<Path<'a>>)>,
 }
 
 impl<'a> LifetimeBounds<'a> {
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 2074a6bfab9..85d4e157b7b 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -227,6 +227,10 @@ pub trait Folder {
         noop_fold_trait_ref(p, self)
     }
 
+    fn fold_poly_trait_ref(&mut self, p: PolyTraitRef) -> PolyTraitRef {
+        noop_fold_poly_trait_ref(p, self)
+    }
+
     fn fold_struct_def(&mut self, struct_def: P<StructDef>) -> P<StructDef> {
         noop_fold_struct_def(struct_def, self)
     }
@@ -442,7 +446,10 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
             TyFixedLengthVec(ty, e) => {
                 TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e))
             }
-            TyTypeof(expr) => TyTypeof(fld.fold_expr(expr))
+            TyTypeof(expr) => TyTypeof(fld.fold_expr(expr)),
+            TyPolyTraitRef(poly_trait_ref) => {
+                TyPolyTraitRef(poly_trait_ref.map(|p| fld.fold_poly_trait_ref(p)))
+            },
         },
         span: fld.new_span(span)
     })
@@ -711,7 +718,7 @@ pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T)
                                    -> TyParamBound
                                    where T: Folder {
     match tpb {
-        TraitTyParamBound(ty) => TraitTyParamBound(fld.fold_trait_ref(ty)),
+        TraitTyParamBound(ty) => TraitTyParamBound(fld.fold_poly_trait_ref(ty)),
         RegionTyParamBound(lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)),
     }
 }
@@ -722,7 +729,7 @@ pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam {
         id: fld.new_id(id),
         ident: ident,
         bounds: fld.fold_bounds(bounds),
-        unbound: unbound.map(|x| fld.fold_ty_param_bound(x)),
+        unbound: unbound.map(|x| fld.fold_trait_ref(x)),
         default: default.map(|x| fld.fold_ty(x)),
         span: span
     }
@@ -842,13 +849,18 @@ pub fn noop_fold_trait_ref<T: Folder>(p: TraitRef, fld: &mut T) -> TraitRef {
     let id = fld.new_id(p.ref_id);
     let TraitRef {
         path,
-        lifetimes,
-        ..
+        ref_id: _,
     } = p;
     ast::TraitRef {
         path: fld.fold_path(path),
         ref_id: id,
-        lifetimes: fld.fold_lifetime_defs(lifetimes),
+    }
+}
+
+pub fn noop_fold_poly_trait_ref<T: Folder>(p: PolyTraitRef, fld: &mut T) -> PolyTraitRef {
+    ast::PolyTraitRef {
+        bound_lifetimes: fld.fold_lifetime_defs(p.bound_lifetimes),
+        trait_ref: fld.fold_trait_ref(p.trait_ref)
     }
 }
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 9ba11d63da5..6873c015fd5 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -42,6 +42,7 @@ use ast::{Method, MutTy, BiMul, Mutability};
 use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot};
 use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct};
 use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle};
+use ast::{PolyTraitRef};
 use ast::{QPath, RequiredMethod};
 use ast::{RetStyle, Return, BiShl, BiShr, Stmt, StmtDecl};
 use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField};
@@ -53,7 +54,7 @@ use ast::{TtDelimited, TtSequence, TtToken};
 use ast::{TupleVariantKind, Ty, Ty_, TyBot};
 use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn};
 use ast::{TyTypeof, TyInfer, TypeMethod};
-use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyQPath};
+use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath};
 use ast::{TyRptr, TyTup, TyU32, TyUniq, TyVec, UnUniq};
 use ast::{TypeImplItem, TypeTraitItem, Typedef, UnboxedClosureKind};
 use ast::{UnnamedField, UnsafeBlock};
@@ -968,30 +969,14 @@ impl<'a> Parser<'a> {
     /// Is the current token one of the keywords that signals a bare function
     /// type?
     pub fn token_is_bare_fn_keyword(&mut self) -> bool {
-        if self.token.is_keyword(keywords::Fn) {
-            return true
-        }
-
-        if self.token.is_keyword(keywords::Unsafe) ||
-            self.token.is_keyword(keywords::Once) {
-            return self.look_ahead(1, |t| t.is_keyword(keywords::Fn))
-        }
-
-        false
+        self.token.is_keyword(keywords::Fn) ||
+            self.token.is_keyword(keywords::Unsafe) ||
+            self.token.is_keyword(keywords::Extern)
     }
 
     /// Is the current token one of the keywords that signals a closure type?
     pub fn token_is_closure_keyword(&mut self) -> bool {
-        self.token.is_keyword(keywords::Unsafe) ||
-            self.token.is_keyword(keywords::Once)
-    }
-
-    /// Is the current token one of the keywords that signals an old-style
-    /// closure type (with explicit sigil)?
-    pub fn token_is_old_style_closure_keyword(&mut self) -> bool {
-        self.token.is_keyword(keywords::Unsafe) ||
-            self.token.is_keyword(keywords::Once) ||
-            self.token.is_keyword(keywords::Fn)
+        self.token.is_keyword(keywords::Unsafe)
     }
 
     pub fn get_lifetime(&mut self) -> ast::Ident {
@@ -1001,8 +986,57 @@ impl<'a> Parser<'a> {
         }
     }
 
+    pub fn parse_for_in_type(&mut self) -> Ty_ {
+        /*
+        Parses whatever can come after a `for` keyword in a type.
+        The `for` has already been consumed.
+
+        Deprecated:
+
+        - for <'lt> |S| -> T
+        - for <'lt> proc(S) -> T
+
+        Eventually:
+
+        - for <'lt> [unsafe] [extern "ABI"] fn (S) -> T
+        - for <'lt> path::foo(a, b)
+
+        */
+
+        // parse <'lt>
+        let lifetime_defs = self.parse_late_bound_lifetime_defs();
+
+        // examine next token to decide to do
+        if self.eat_keyword(keywords::Proc) {
+            self.parse_proc_type(lifetime_defs)
+        } else if self.token_is_bare_fn_keyword() || self.token_is_closure_keyword() {
+            self.parse_ty_bare_fn_or_ty_closure(lifetime_defs)
+        } else if self.token == token::ModSep ||
+                  self.token.is_ident() ||
+                  self.token.is_path() {
+            let trait_ref = self.parse_trait_ref();
+            TyPolyTraitRef(P(PolyTraitRef { bound_lifetimes: lifetime_defs,
+                                            trait_ref: trait_ref }))
+        } else {
+            self.parse_ty_closure(lifetime_defs)
+        }
+    }
+
+    pub fn parse_ty_path(&mut self, plus_allowed: bool) -> Ty_ {
+        let mode = if plus_allowed {
+            LifetimeAndTypesAndBounds
+        } else {
+            LifetimeAndTypesWithoutColons
+        };
+        let PathAndBounds {
+            path,
+            bounds
+        } = self.parse_path(mode);
+        TyPath(path, bounds, ast::DUMMY_NODE_ID)
+    }
+
     /// parse a TyBareFn type:
-    pub fn parse_ty_bare_fn(&mut self) -> Ty_ {
+    pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec<ast::LifetimeDef>) -> Ty_ {
         /*
 
         [unsafe] [extern "ABI"] fn <'lt> (S) -> T
@@ -1023,18 +1057,26 @@ impl<'a> Parser<'a> {
         };
 
         self.expect_keyword(keywords::Fn);
-        let (decl, lifetimes) = self.parse_ty_fn_decl(true);
+        let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs);
+        let (inputs, variadic) = self.parse_fn_args(false, true);
+        let (ret_style, ret_ty) = self.parse_ret_ty();
+        let decl = P(FnDecl {
+            inputs: inputs,
+            output: ret_ty,
+            cf: ret_style,
+            variadic: variadic
+        });
         TyBareFn(P(BareFnTy {
             abi: abi,
             fn_style: fn_style,
-            lifetimes: lifetimes,
+            lifetimes: lifetime_defs,
             decl: decl
         }))
     }
 
     /// Parses a procedure type (`proc`). The initial `proc` keyword must
     /// already have been parsed.
-    pub fn parse_proc_type(&mut self) -> Ty_ {
+    pub fn parse_proc_type(&mut self, lifetime_defs: Vec<ast::LifetimeDef>) -> Ty_ {
         /*
 
         proc <'lt> (S) [:Bounds] -> T
@@ -1043,19 +1085,12 @@ impl<'a> Parser<'a> {
          |     |    |      |      Return type
          |     |    |    Bounds
          |     |  Argument types
-         |   Lifetimes
+         |   Legacy lifetimes
         the `proc` keyword
 
         */
 
-        let lifetime_defs = if self.eat(&token::Lt) {
-            let lifetime_defs = self.parse_lifetime_defs();
-            self.expect_gt();
-            lifetime_defs
-        } else {
-            Vec::new()
-        };
-
+        let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs);
         let (inputs, variadic) = self.parse_fn_args(false, false);
         let bounds = self.parse_colon_then_ty_param_bounds();
         let (ret_style, ret_ty) = self.parse_ret_ty();
@@ -1100,33 +1135,49 @@ impl<'a> Parser<'a> {
         return None
     }
 
+    pub fn parse_ty_bare_fn_or_ty_closure(&mut self, lifetime_defs: Vec<LifetimeDef>) -> Ty_ {
+        // Both bare fns and closures can begin with stuff like unsafe
+        // and extern. So we just scan ahead a few tokens to see if we see
+        // a `fn`.
+        //
+        // Closure:  [unsafe] <'lt> |S| [:Bounds] -> T
+        // Fn:       [unsafe] [extern "ABI"] fn <'lt> (S) -> T
+
+        if self.token.is_keyword(keywords::Fn) {
+            self.parse_ty_bare_fn(lifetime_defs)
+        } else if self.token.is_keyword(keywords::Extern) {
+            self.parse_ty_bare_fn(lifetime_defs)
+        } else if self.token.is_keyword(keywords::Unsafe) {
+            if self.look_ahead(1, |t| t.is_keyword(keywords::Fn) ||
+                                      t.is_keyword(keywords::Extern)) {
+                self.parse_ty_bare_fn(lifetime_defs)
+            } else {
+                self.parse_ty_closure(lifetime_defs)
+            }
+        } else {
+            self.parse_ty_closure(lifetime_defs)
+        }
+    }
+
     /// Parse a TyClosure type
-    pub fn parse_ty_closure(&mut self) -> Ty_ {
+    pub fn parse_ty_closure(&mut self, lifetime_defs: Vec<ast::LifetimeDef>) -> Ty_ {
         /*
 
-        [unsafe] [once] <'lt> |S| [:Bounds] -> T
-        ^~~~~~~^ ^~~~~^ ^~~~^  ^  ^~~~~~~~^    ^
-          |        |      |    |      |        |
-          |        |      |    |      |      Return type
-          |        |      |    |  Closure bounds
-          |        |      |  Argument types
-          |        |    Lifetime defs
-          |     Once-ness (a.k.a., affine)
+        [unsafe] <'lt> |S| [:Bounds] -> T
+        ^~~~~~~^ ^~~~^  ^  ^~~~~~~~^    ^
+          |        |       |      |        |
+          |        |       |      |      Return type
+          |        |       |  Closure bounds
+          |        |     Argument types
+          |      Deprecated lifetime defs
+          |
         Function Style
 
         */
 
         let fn_style = self.parse_unsafety();
-        let onceness = if self.eat_keyword(keywords::Once) {Once} else {Many};
 
-        let lifetime_defs = if self.eat(&token::Lt) {
-            let lifetime_defs = self.parse_lifetime_defs();
-            self.expect_gt();
-
-            lifetime_defs
-        } else {
-            Vec::new()
-        };
+        let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs);
 
         let inputs = if self.eat(&token::OrOr) {
             Vec::new()
@@ -1152,7 +1203,7 @@ impl<'a> Parser<'a> {
 
         TyClosure(P(ClosureTy {
             fn_style: fn_style,
-            onceness: onceness,
+            onceness: Many,
             bounds: bounds,
             decl: decl,
             lifetimes: lifetime_defs,
@@ -1167,36 +1218,23 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Parse a function type (following the 'fn')
-    pub fn parse_ty_fn_decl(&mut self, allow_variadic: bool)
-                            -> (P<FnDecl>, Vec<ast::LifetimeDef>) {
-        /*
-
-        (fn) <'lt> (S) -> T
-             ^~~~^ ^~^    ^
-               |    |     |
-               |    |   Return type
-               |  Argument types
-           Lifetime_defs
-
-        */
-        let lifetime_defs = if self.eat(&token::Lt) {
-            let lifetime_defs = self.parse_lifetime_defs();
-            self.expect_gt();
-            lifetime_defs
+    /// Parses `[ 'for' '<' lifetime_defs '>' ]'
+    fn parse_legacy_lifetime_defs(&mut self,
+                                  lifetime_defs: Vec<ast::LifetimeDef>)
+                                  -> Vec<ast::LifetimeDef>
+    {
+        if self.eat(&token::Lt) {
+            if lifetime_defs.is_empty() {
+                self.warn("deprecated syntax, use `for` keyword now");
+                let lifetime_defs = self.parse_lifetime_defs();
+                self.expect_gt();
+                lifetime_defs
+            } else {
+                self.fatal("cannot use new `for` keyword and older syntax together");
+            }
         } else {
-            Vec::new()
-        };
-
-        let (inputs, variadic) = self.parse_fn_args(false, allow_variadic);
-        let (ret_style, ret_ty) = self.parse_ret_ty();
-        let decl = P(FnDecl {
-            inputs: inputs,
-            output: ret_ty,
-            cf: ret_style,
-            variadic: variadic
-        });
-        (decl, lifetime_defs)
+            lifetime_defs
+        }
     }
 
     /// Parses `type Foo;` in a trait declaration only. The `type` keyword has
@@ -1433,25 +1471,24 @@ impl<'a> Parser<'a> {
             self.expect(&token::CloseDelim(token::Bracket));
             t
         } else if self.token == token::BinOp(token::And) ||
-                self.token == token::AndAnd {
+                  self.token == token::AndAnd {
             // BORROWED POINTER
             self.expect_and();
             self.parse_borrowed_pointee()
-        } else if self.token.is_keyword(keywords::Extern) ||
-                  self.token.is_keyword(keywords::Unsafe) ||
-                self.token_is_bare_fn_keyword() {
-            // BARE FUNCTION
-            self.parse_ty_bare_fn()
-        } else if self.token_is_closure_keyword() ||
-                self.token == token::BinOp(token::Or) ||
-                self.token == token::OrOr ||
-                (self.token == token::Lt &&
-                 self.look_ahead(1, |t| {
-                     *t == token::Gt || t.is_lifetime()
-                 })) {
+        } else if self.token.is_keyword(keywords::For) {
+            self.parse_for_in_type()
+        } else if self.token_is_bare_fn_keyword() ||
+                  self.token_is_closure_keyword() {
+            // BARE FUNCTION OR CLOSURE
+            self.parse_ty_bare_fn_or_ty_closure(Vec::new())
+        } else if self.token == token::BinOp(token::Or) ||
+                  self.token == token::OrOr ||
+                  (self.token == token::Lt &&
+                   self.look_ahead(1, |t| {
+                       *t == token::Gt || t.is_lifetime()
+                   })) {
             // CLOSURE
-
-            self.parse_ty_closure()
+            self.parse_ty_closure(Vec::new())
         } else if self.eat_keyword(keywords::Typeof) {
             // TYPEOF
             // In order to not be ambiguous, the type must be surrounded by parens.
@@ -1460,7 +1497,7 @@ impl<'a> Parser<'a> {
             self.expect(&token::CloseDelim(token::Paren));
             TyTypeof(e)
         } else if self.eat_keyword(keywords::Proc) {
-            self.parse_proc_type()
+            self.parse_proc_type(Vec::new())
         } else if self.token == token::Lt {
             // QUALIFIED PATH
             self.bump();
@@ -1479,16 +1516,7 @@ impl<'a> Parser<'a> {
                   self.token.is_ident() ||
                   self.token.is_path() {
             // NAMED TYPE
-            let mode = if plus_allowed {
-                LifetimeAndTypesAndBounds
-            } else {
-                LifetimeAndTypesWithoutColons
-            };
-            let PathAndBounds {
-                path,
-                bounds
-            } = self.parse_path(mode);
-            TyPath(path, bounds, ast::DUMMY_NODE_ID)
+            self.parse_ty_path(plus_allowed)
         } else if self.eat(&token::Underscore) {
             // TYPE TO BE INFERRED
             TyInfer
@@ -3848,29 +3876,17 @@ impl<'a> Parser<'a> {
     }
 
     // matches bounds    = ( boundseq )?
-    // where   boundseq  = ( bound + boundseq ) | bound
-    // and     bound     = 'region | ty
+    // where   boundseq  = ( polybound + boundseq ) | polybound
+    // and     polybound = ( 'for' '<' 'region '>' )? bound
+    // and     bound     = 'region | trait_ref
     // NB: The None/Some distinction is important for issue #7264.
     fn parse_ty_param_bounds(&mut self)
                              -> OwnedSlice<TyParamBound>
     {
         let mut result = vec!();
         loop {
-            let lifetime_defs = if self.eat(&token::Lt) {
-                let lifetime_defs = self.parse_lifetime_defs();
-                self.expect_gt();
-                lifetime_defs
-            } else {
-                Vec::new()
-            };
             match self.token {
                 token::Lifetime(lifetime) => {
-                    if lifetime_defs.len() > 0 {
-                        let span = self.last_span;
-                        self.span_err(span, "lifetime declarations are not \
-                                             allowed here")
-                    }
-
                     result.push(RegionTyParamBound(ast::Lifetime {
                         id: ast::DUMMY_NODE_ID,
                         span: self.span,
@@ -3879,13 +3895,8 @@ impl<'a> Parser<'a> {
                     self.bump();
                 }
                 token::ModSep | token::Ident(..) => {
-                    let path =
-                        self.parse_path(LifetimeAndTypesWithoutColons).path;
-                    result.push(TraitTyParamBound(ast::TraitRef {
-                        path: path,
-                        ref_id: ast::DUMMY_NODE_ID,
-                        lifetimes: lifetime_defs,
-                    }))
+                    let poly_trait_ref = self.parse_poly_trait_ref();
+                    result.push(TraitTyParamBound(poly_trait_ref))
                 }
                 _ => break,
             }
@@ -3898,7 +3909,7 @@ impl<'a> Parser<'a> {
         return OwnedSlice::from_vec(result);
     }
 
-    fn trait_ref_from_ident(ident: Ident, span: Span) -> ast::TraitRef {
+    fn trait_ref_from_ident(ident: Ident, span: Span) -> TraitRef {
         let segment = ast::PathSegment {
             identifier: ident,
             parameters: ast::PathParameters::none()
@@ -3911,7 +3922,6 @@ impl<'a> Parser<'a> {
         ast::TraitRef {
             path: path,
             ref_id: ast::DUMMY_NODE_ID,
-            lifetimes: Vec::new(),
         }
     }
 
@@ -3927,7 +3937,7 @@ impl<'a> Parser<'a> {
         let mut unbound = None;
         if self.eat(&token::Question) {
             let tref = Parser::trait_ref_from_ident(ident, span);
-            unbound = Some(TraitTyParamBound(tref));
+            unbound = Some(tref);
             span = self.span;
             ident = self.parse_ident();
         }
@@ -4538,7 +4548,6 @@ impl<'a> Parser<'a> {
                     Some(TraitRef {
                         path: (*path).clone(),
                         ref_id: node_id,
-                        lifetimes: Vec::new(),
                     })
                 }
                 TyPath(_, Some(_), _) => {
@@ -4568,6 +4577,35 @@ impl<'a> Parser<'a> {
          Some(attrs))
     }
 
+    /// Parse a::B<String,int>
+    fn parse_trait_ref(&mut self) -> TraitRef {
+        ast::TraitRef {
+            path: self.parse_path(LifetimeAndTypesWithoutColons).path,
+            ref_id: ast::DUMMY_NODE_ID,
+        }
+    }
+
+    fn parse_late_bound_lifetime_defs(&mut self) -> Vec<ast::LifetimeDef> {
+        if self.eat_keyword(keywords::For) {
+            self.expect(&token::Lt);
+            let lifetime_defs = self.parse_lifetime_defs();
+            self.expect_gt();
+            lifetime_defs
+        } else {
+            Vec::new()
+        }
+    }
+
+    /// Parse for<'l> a::B<String,int>
+    fn parse_poly_trait_ref(&mut self) -> PolyTraitRef {
+        let lifetime_defs = self.parse_late_bound_lifetime_defs();
+
+        ast::PolyTraitRef {
+            bound_lifetimes: lifetime_defs,
+            trait_ref: self.parse_trait_ref()
+        }
+    }
+
     /// Parse struct Foo { ... }
     fn parse_item_struct(&mut self) -> ItemInfo {
         let class_name = self.parse_ident();
@@ -4681,7 +4719,7 @@ impl<'a> Parser<'a> {
         else { Inherited }
     }
 
-    fn parse_for_sized(&mut self) -> Option<ast::TyParamBound> {
+    fn parse_for_sized(&mut self) -> Option<ast::TraitRef> {
         if self.eat_keyword(keywords::For) {
             let span = self.span;
             let ident = self.parse_ident();
@@ -4691,7 +4729,7 @@ impl<'a> Parser<'a> {
                 return None;
             }
             let tref = Parser::trait_ref_from_ident(ident, span);
-            Some(TraitTyParamBound(tref))
+            Some(tref)
         } else {
             None
         }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 63e2c5499e8..5b57a875c4a 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -743,6 +743,9 @@ impl<'a> State<'a> {
             ast::TyPath(ref path, ref bounds, _) => {
                 try!(self.print_bounded_path(path, bounds));
             }
+            ast::TyPolyTraitRef(ref poly_trait_ref) => {
+                try!(self.print_poly_trait_ref(&**poly_trait_ref));
+            }
             ast::TyQPath(ref qpath) => {
                 try!(word(&mut self.s, "<"));
                 try!(self.print_type(&*qpath.for_type));
@@ -960,7 +963,7 @@ impl<'a> State<'a> {
                 try!(self.print_ident(item.ident));
                 try!(self.print_generics(generics));
                 match unbound {
-                    &Some(TraitTyParamBound(ref tref)) => {
+                    &Some(ref tref) => {
                         try!(space(&mut self.s));
                         try!(self.word_space("for"));
                         try!(self.print_trait_ref(tref));
@@ -995,19 +998,21 @@ impl<'a> State<'a> {
     }
 
     fn print_trait_ref(&mut self, t: &ast::TraitRef) -> IoResult<()> {
-        if t.lifetimes.len() > 0 {
-            try!(self.print_generics(&ast::Generics {
-                lifetimes: t.lifetimes.clone(),
-                ty_params: OwnedSlice::empty(),
-                where_clause: ast::WhereClause {
-                    id: ast::DUMMY_NODE_ID,
-                    predicates: Vec::new(),
-                },
-            }));
-        }
         self.print_path(&t.path, false)
     }
 
+    fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) -> IoResult<()> {
+        if !t.bound_lifetimes.is_empty() {
+            try!(word(&mut self.s, "for<"));
+            for lifetime_def in t.bound_lifetimes.iter() {
+                try!(self.print_lifetime_def(lifetime_def));
+            }
+            try!(word(&mut self.s, ">"));
+        }
+
+        self.print_trait_ref(&t.trait_ref)
+    }
+
     pub fn print_enum_def(&mut self, enum_definition: &ast::EnumDef,
                           generics: &ast::Generics, ident: ast::Ident,
                           span: codemap::Span,
@@ -2383,7 +2388,7 @@ impl<'a> State<'a> {
 
                 try!(match *bound {
                     TraitTyParamBound(ref tref) => {
-                        self.print_trait_ref(tref)
+                        self.print_poly_trait_ref(tref)
                     }
                     RegionTyParamBound(ref lt) => {
                         self.print_lifetime(lt)
@@ -2450,7 +2455,7 @@ impl<'a> State<'a> {
 
     pub fn print_ty_param(&mut self, param: &ast::TyParam) -> IoResult<()> {
         match param.unbound {
-            Some(TraitTyParamBound(ref tref)) => {
+            Some(ref tref) => {
                 try!(self.print_trait_ref(tref));
                 try!(self.word_space("?"));
             }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 9751abacbd3..1b1d1e9cace 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -75,6 +75,10 @@ pub trait Visitor<'v> {
     }
     fn visit_ty_method(&mut self, t: &'v TypeMethod) { walk_ty_method(self, t) }
     fn visit_trait_item(&mut self, t: &'v TraitItem) { walk_trait_item(self, t) }
+    fn visit_trait_ref(&mut self, t: &'v TraitRef) { walk_trait_ref(self, t) }
+    fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef) {
+        walk_poly_trait_ref(self, t)
+    }
     fn visit_struct_def(&mut self, s: &'v StructDef, _: Ident, _: &'v Generics, _: NodeId) {
         walk_struct_def(self, s)
     }
@@ -202,9 +206,20 @@ pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V,
 
 /// Like with walk_method_helper this doesn't correspond to a method
 /// in Visitor, and so it gets a _helper suffix.
-pub fn walk_trait_ref_helper<'v,V>(visitor: &mut V, trait_ref: &'v TraitRef)
-                                   where V: Visitor<'v> {
-    walk_lifetime_decls(visitor, &trait_ref.lifetimes);
+pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V,
+                                         trait_ref: &'v PolyTraitRef)
+    where V: Visitor<'v>
+{
+    walk_lifetime_decls(visitor, &trait_ref.bound_lifetimes);
+    visitor.visit_trait_ref(&trait_ref.trait_ref);
+}
+
+/// Like with walk_method_helper this doesn't correspond to a method
+/// in Visitor, and so it gets a _helper suffix.
+pub fn walk_trait_ref<'v,V>(visitor: &mut V,
+                                   trait_ref: &'v TraitRef)
+    where V: Visitor<'v>
+{
     visitor.visit_path(&trait_ref.path, trait_ref.ref_id)
 }
 
@@ -248,8 +263,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
                  ref impl_items) => {
             visitor.visit_generics(type_parameters);
             match *trait_reference {
-                Some(ref trait_reference) => walk_trait_ref_helper(visitor,
-                                                                   trait_reference),
+                Some(ref trait_reference) => visitor.visit_trait_ref(trait_reference),
                 None => ()
             }
             visitor.visit_ty(&**typ);
@@ -383,6 +397,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
             visitor.visit_ty(&**ty);
             visitor.visit_expr(&**expression)
         }
+        TyPolyTraitRef(ref poly_trait_ref) => {
+            visitor.visit_poly_trait_ref(&**poly_trait_ref)
+        }
         TyTypeof(ref expression) => {
             visitor.visit_expr(&**expression)
         }
@@ -497,7 +514,7 @@ pub fn walk_ty_param_bounds<'v, V: Visitor<'v>>(visitor: &mut V,
     for bound in bounds.iter() {
         match *bound {
             TraitTyParamBound(ref typ) => {
-                walk_trait_ref_helper(visitor, typ)
+                visitor.visit_poly_trait_ref(typ)
             }
             RegionTyParamBound(ref lifetime) => {
                 visitor.visit_lifetime_ref(lifetime);
diff --git a/src/test/compile-fail/issue-10291.rs b/src/test/compile-fail/issue-10291.rs
index 995ae7b3d44..924132c6de2 100644
--- a/src/test/compile-fail/issue-10291.rs
+++ b/src/test/compile-fail/issue-10291.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 fn test<'x>(x: &'x int) {
-    drop::< <'z>|&'z int| -> &'z int >(|z| {
+    drop::< for<'z>|&'z int| -> &'z int >(|z| {
         x
         //~^ ERROR cannot infer an appropriate lifetime
     });
diff --git a/src/test/compile-fail/regions-fn-subtyping-return-static.rs b/src/test/compile-fail/regions-fn-subtyping-return-static.rs
index 4c90b1f0eea..ac56e8ce14d 100644
--- a/src/test/compile-fail/regions-fn-subtyping-return-static.rs
+++ b/src/test/compile-fail/regions-fn-subtyping-return-static.rs
@@ -22,11 +22,11 @@
 struct S;
 
 // Given 'cx, return 'cx
-type F = fn<'cx>(&'cx S) -> &'cx S;
+type F = for<'cx> fn(&'cx S) -> &'cx S;
 fn want_F(f: F) { }
 
 // Given anything, return 'static
-type G = fn<'cx>(&'cx S) -> &'static S;
+type G = for<'cx> fn(&'cx S) -> &'static S;
 fn want_G(f: G) { }
 
 // Should meet both.
diff --git a/src/test/compile-fail/regions-fn-subtyping.rs b/src/test/compile-fail/regions-fn-subtyping.rs
index 8e8d892a39f..91a6ff789ea 100644
--- a/src/test/compile-fail/regions-fn-subtyping.rs
+++ b/src/test/compile-fail/regions-fn-subtyping.rs
@@ -17,29 +17,29 @@ fn test_fn<'x,'y,'z,T>(_x: &'x T, _y: &'y T, _z: &'z T) {
     // subtype::<T1>(of::<T2>()) will typecheck
     // iff T1 <: T2.
 
-    subtype::< <'a>|&'a T|>(
-        of::< <'a>|&'a T|>());
+    subtype::< for<'a>|&'a T|>(
+        of::< for<'a>|&'a T|>());
 
-    subtype::< <'a>|&'a T|>(
-        of::< <'b>|&'b T|>());
+    subtype::< for<'a>|&'a T|>(
+        of::< for<'b>|&'b T|>());
 
-    subtype::< <'b>|&'b T|>(
+    subtype::< for<'b>|&'b T|>(
         of::<|&'x T|>());
 
     subtype::<|&'x T|>(
-        of::< <'b>|&'b T|>());  //~ ERROR mismatched types
+        of::< for<'b>|&'b T|>());  //~ ERROR mismatched types
 
-    subtype::< <'a,'b>|&'a T, &'b T|>(
-        of::< <'a>|&'a T, &'a T|>());
+    subtype::< for<'a,'b>|&'a T, &'b T|>(
+        of::< for<'a>|&'a T, &'a T|>());
 
-    subtype::< <'a>|&'a T, &'a T|>(
-        of::< <'a,'b>|&'a T, &'b T|>()); //~ ERROR mismatched types
+    subtype::< for<'a>|&'a T, &'a T|>(
+        of::< for<'a,'b>|&'a T, &'b T|>()); //~ ERROR mismatched types
 
-    subtype::< <'a,'b>|&'a T, &'b T|>(
+    subtype::< for<'a,'b>|&'a T, &'b T|>(
         of::<|&'x T, &'y T|>());
 
     subtype::<|&'x T, &'y T|>(
-        of::< <'a,'b>|&'a T, &'b T|>()); //~ ERROR mismatched types
+        of::< for<'a,'b>|&'a T, &'b T|>()); //~ ERROR mismatched types
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/regions-name-undeclared.rs b/src/test/compile-fail/regions-name-undeclared.rs
index ba3d7bd29f4..e9e585e84d0 100644
--- a/src/test/compile-fail/regions-name-undeclared.rs
+++ b/src/test/compile-fail/regions-name-undeclared.rs
@@ -43,16 +43,16 @@ fn bar<'a>(x: &'a int) {
 
     // &'a CAN be declared on functions and used then:
     fn g<'a>(a: &'a int) { } // OK
-    fn h(a: <'a>|&'a int|) { } // OK
+    fn h(a: for<'a>|&'a int|) { } // OK
 }
 
 // Test nesting of lifetimes in fn type declarations
 fn fn_types(a: &'a int, //~ ERROR undeclared lifetime
-            b: <'a>|a: &'a int,
-                    b: &'b int, //~ ERROR undeclared lifetime
-                    c: <'b>|a: &'a int,
-                            b: &'b int|,
-                    d: &'b int|, //~ ERROR undeclared lifetime
+            b: for<'a>|a: &'a int,
+                       b: &'b int, //~ ERROR undeclared lifetime
+                       c: for<'b>|a: &'a int,
+                                  b: &'b int|,
+                       d: &'b int|, //~ ERROR undeclared lifetime
             c: &'a int) //~ ERROR undeclared lifetime
 {
 }
diff --git a/src/test/compile-fail/regions-nested-fns-2.rs b/src/test/compile-fail/regions-nested-fns-2.rs
index 60eae9ce80a..a08cf226389 100644
--- a/src/test/compile-fail/regions-nested-fns-2.rs
+++ b/src/test/compile-fail/regions-nested-fns-2.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn ignore(_f: <'z>|&'z int| -> &'z int) {}
+fn ignore(_f: for<'z>|&'z int| -> &'z int) {}
 
 fn nested() {
     let y = 3;
diff --git a/src/test/compile-fail/regions-nested-fns.rs b/src/test/compile-fail/regions-nested-fns.rs
index 7dc57d37e24..cf0b615bb01 100644
--- a/src/test/compile-fail/regions-nested-fns.rs
+++ b/src/test/compile-fail/regions-nested-fns.rs
@@ -14,13 +14,13 @@ fn nested<'x>(x: &'x int) {
     let y = 3;
     let mut ay = &y; //~ ERROR cannot infer
 
-    ignore::< <'z>|&'z int|>(|z| {
+    ignore::< for<'z>|&'z int|>(|z| {
         ay = x;
         ay = &y;
         ay = z;
     });
 
-    ignore::< <'z>|&'z int| -> &'z int>(|z| {
+    ignore::< for<'z>|&'z int| -> &'z int>(|z| {
         if false { return x; }  //~ ERROR cannot infer an appropriate lifetime for automatic
         if false { return ay; }
         return z;
diff --git a/src/test/compile-fail/regions-ret-borrowed-1.rs b/src/test/compile-fail/regions-ret-borrowed-1.rs
index 6d9b2619171..997775efa84 100644
--- a/src/test/compile-fail/regions-ret-borrowed-1.rs
+++ b/src/test/compile-fail/regions-ret-borrowed-1.rs
@@ -12,7 +12,7 @@
 // some point regions-ret-borrowed reported an error but this file did
 // not, due to special hardcoding around the anonymous region.
 
-fn with<R>(f: <'a>|x: &'a int| -> R) -> R {
+fn with<R>(f: for<'a>|x: &'a int| -> R) -> R {
     f(&3)
 }
 
diff --git a/src/test/run-pass/hrtb-parse.rs b/src/test/run-pass/hrtb-parse.rs
new file mode 100644
index 00000000000..080523f0060
--- /dev/null
+++ b/src/test/run-pass/hrtb-parse.rs
@@ -0,0 +1,48 @@
+// 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.
+
+// Test that we can parse all the various places that a `for` keyword
+// can appear representing universal quantification.
+
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+trait Get<A,R> {
+    fn get(&self, arg: A) -> R;
+}
+
+// Parse HRTB with explicit `for` in a where-clause:
+
+fn foo00<T>(t: T)
+    where T : for<'a> Get<&'a int, &'a int>
+{
+}
+
+fn foo01<T: for<'a> Get<&'a int, &'a int>>(t: T)
+{
+}
+
+// Parse HRTB with explicit `for` in various sorts of types:
+
+fn foo10(t: Box<for<'a> Get<int, int>>) { }
+fn foo11(t: Box<for<'a> Get(int) -> int>) { }
+
+fn foo20(t: for<'a> fn(int) -> int) { }
+fn foo21(t: for<'a> unsafe fn(int) -> int) { }
+fn foo22(t: for<'a> extern "C" fn(int) -> int) { }
+fn foo23(t: for<'a> unsafe extern "C" fn(int) -> int) { }
+
+fn foo30(t: for<'a> |int| -> int) { }
+fn foo31(t: for<'a> unsafe |int| -> int) { }
+
+//fn foo40(t: for<'a> proc(int) -> int) { }
+
+fn main() {
+}
diff --git a/src/test/run-pass/nullable-pointer-ffi-compat.rs b/src/test/run-pass/nullable-pointer-ffi-compat.rs
index b5c541b0c63..32432c07dcf 100644
--- a/src/test/run-pass/nullable-pointer-ffi-compat.rs
+++ b/src/test/run-pass/nullable-pointer-ffi-compat.rs
@@ -29,7 +29,7 @@ static FOO: int = 0xDEADBEE;
 
 pub fn main() {
     unsafe {
-        let f: extern "C" fn<'a>(&'a int) -> &'a int = mem::transmute(foo);
+        let f: for<'a> extern "C" fn(&'a int) -> &'a int = mem::transmute(foo);
         assert_eq!(*f(&FOO), FOO);
     }
 }