about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-11-09 03:51:41 +0000
committerbors <bors@rust-lang.org>2014-11-09 03:51:41 +0000
commita2f303ad098844351d08800038a4f99fa2ff0817 (patch)
tree8ab2d0ef6dc8abb598082f43f8496911bdc4c470
parent93c85eb8bdcc910a27caf6abd20207a626ae98e5 (diff)
parentcf4e53eee7377b42524176f39b0b428175c74fb1 (diff)
downloadrust-a2f303ad098844351d08800038a4f99fa2ff0817.tar.gz
rust-a2f303ad098844351d08800038a4f99fa2ff0817.zip
auto merge of #18743 : nikomatsakis/rust/hrtb-refactor-2, r=pcwalton
Various miscellaneous changes pushing towards HRTB support:

1. Update parser and adjust ast to support `for<'a,'b>` syntax, both in closures and trait bounds. Warn on the old syntax (not error, for stage0).
2. Refactor TyTrait representation to include a TraitRef.
3. Purge `once_fns` feature gate and `once` keyword.

r? @pcwalton 

This is a [breaking-change]:

- The `once_fns` feature is now officially deprecated. Rewrite using normal closures or unboxed closures.
- The new `for`-based syntax now issues warnings (but not yet errors):
  - `fn<'a>(T) -> U` becomes `for<'a> fn(T) -> U`
  - `<'a> |T| -> U` becomes `for<'a> |T| -> U`
-rw-r--r--src/librustc/lint/builtin.rs4
-rw-r--r--src/librustc/metadata/tydecode.rs5
-rw-r--r--src/librustc/metadata/tyencode.rs11
-rw-r--r--src/librustc/middle/astencode.rs42
-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/traits/coherence.rs2
-rw-r--r--src/librustc/middle/trans/debuginfo.rs10
-rw-r--r--src/librustc/middle/trans/expr.rs6
-rw-r--r--src/librustc/middle/ty.rs69
-rw-r--r--src/librustc/middle/ty_fold.rs16
-rw-r--r--src/librustc/middle/typeck/astconv.rs128
-rw-r--r--src/librustc/middle/typeck/check/method.rs45
-rw-r--r--src/librustc/middle/typeck/check/vtable.rs13
-rw-r--r--src/librustc/middle/typeck/coherence/mod.rs8
-rw-r--r--src/librustc/middle/typeck/coherence/orphan.rs25
-rw-r--r--src/librustc/middle/typeck/collect.rs99
-rw-r--r--src/librustc/middle/typeck/infer/coercion.rs29
-rw-r--r--src/librustc/middle/typeck/infer/combine.rs11
-rw-r--r--src/librustc/middle/typeck/infer/error_reporting.rs13
-rw-r--r--src/librustc/middle/typeck/infer/mod.rs10
-rw-r--r--src/librustc/middle/typeck/variance.rs10
-rw-r--r--src/librustc/util/ppaux.rs8
-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/feature_gate.rs10
-rw-r--r--src/libsyntax/fold.rs24
-rw-r--r--src/libsyntax/parse/parser.rs310
-rw-r--r--src/libsyntax/parse/token.rs59
-rw-r--r--src/libsyntax/print/pprust.rs40
-rw-r--r--src/libsyntax/visit.rs29
-rw-r--r--src/test/compile-fail/issue-10291.rs2
-rw-r--r--src/test/compile-fail/once-cant-call-twice-on-stack.rs28
-rw-r--r--src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs27
-rw-r--r--src/test/compile-fail/once-fn-subtyping.rs17
-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-duplicated.rs1
-rw-r--r--src/test/compile-fail/regions-name-static.rs1
-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
-rw-r--r--src/test/run-pass/once-move-out-on-heap.rs1
-rw-r--r--src/test/run-pass/once-move-out-on-stack.rs27
52 files changed, 749 insertions, 737 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/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index 227a6f71bfd..26b2afd2f3c 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -389,11 +389,10 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
       }
       'x' => {
         assert_eq!(next(st), '[');
-        let def = parse_def(st, NominalType, |x,y| conv(x,y));
-        let substs = parse_substs(st, |x,y| conv(x,y));
+        let trait_ref = parse_trait_ref(st, |x,y| conv(x,y));
         let bounds = parse_existential_bounds(st, |x,y| conv(x,y));
         assert_eq!(next(st), ']');
-        return ty::mk_trait(st.tcx, def, substs, bounds);
+        return ty::mk_trait(st.tcx, trait_ref, bounds);
       }
       'p' => {
         let did = parse_def(st, TypeParameter, |x,y| conv(x,y));
diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs
index 027b9980a32..a7b64cb20e5 100644
--- a/src/librustc/metadata/tyencode.rs
+++ b/src/librustc/metadata/tyencode.rs
@@ -231,13 +231,10 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) {
             enc_substs(w, cx, substs);
             mywrite!(w, "]");
         }
-        ty::ty_trait(box ty::TyTrait {
-                def_id,
-                ref substs,
-                ref bounds
-            }) => {
-            mywrite!(w, "x[{}|", (cx.ds)(def_id));
-            enc_substs(w, cx, substs);
+        ty::ty_trait(box ty::TyTrait { ref principal,
+                                       ref bounds }) => {
+            mywrite!(w, "x[");
+            enc_trait_ref(w, cx, principal);
             enc_existential_bounds(w, cx, bounds);
             mywrite!(w, "]");
         }
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 9268418ef94..aaf3b16c5ee 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -1085,16 +1085,19 @@ impl<'a> rbml_writer_helpers for Encoder<'a> {
                         this.emit_enum_variant_arg(1, |this| idx.encode(this))
                     })
                 }
-                ty::UnsizeVtable(ty::TyTrait { def_id,
-                                               bounds: ref b,
-                                               ref substs },
+                ty::UnsizeVtable(ty::TyTrait { ref principal,
+                                               bounds: ref b },
                                  self_ty) => {
                     this.emit_enum_variant("UnsizeVtable", 2, 4, |this| {
-                        this.emit_enum_variant_arg(
-                            0, |this| Ok(this.emit_existential_bounds(ecx, b)));
-                        this.emit_enum_variant_arg(1, |this| def_id.encode(this));
-                        this.emit_enum_variant_arg(2, |this| Ok(this.emit_ty(ecx, self_ty)));
-                        this.emit_enum_variant_arg(3, |this| Ok(this.emit_substs(ecx, substs)))
+                        this.emit_enum_variant_arg(0, |this| {
+                            try!(this.emit_struct_field("principal", 0, |this| {
+                                Ok(this.emit_trait_ref(ecx, &*principal))
+                            }));
+                            this.emit_struct_field("bounds", 1, |this| {
+                                Ok(this.emit_existential_bounds(ecx, b))
+                            })
+                        });
+                        this.emit_enum_variant_arg(1, |this| Ok(this.emit_ty(ecx, self_ty)))
                     })
                 }
             }
@@ -1693,18 +1696,19 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> {
                         ty::UnsizeStruct(box uk, idx)
                     }
                     2 => {
-                        let b =
-                            this.read_enum_variant_arg(
-                                0, |this| Ok(this.read_existential_bounds(dcx))).unwrap();
-                        let def_id: ast::DefId =
-                            this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap();
+                        let ty_trait = try!(this.read_enum_variant_arg(0, |this| {
+                            let principal = try!(this.read_struct_field("principal", 0, |this| {
+                                Ok(this.read_trait_ref(dcx))
+                            }));
+                            Ok(ty::TyTrait {
+                                principal: (*principal).clone(),
+                                bounds: try!(this.read_struct_field("bounds", 1, |this| {
+                                    Ok(this.read_existential_bounds(dcx))
+                                })),
+                            })
+                        }));
                         let self_ty =
-                            this.read_enum_variant_arg(2, |this| Ok(this.read_ty(dcx))).unwrap();
-                        let substs = this.read_enum_variant_arg(3,
-                            |this| Ok(this.read_substs(dcx))).unwrap();
-                        let ty_trait = ty::TyTrait { def_id: def_id.tr(dcx),
-                                                     bounds: b,
-                                                     substs: substs };
+                            this.read_enum_variant_arg(1, |this| Ok(this.read_ty(dcx))).unwrap();
                         ty::UnsizeVtable(ty_trait, self_ty)
                     }
                     _ => panic!("bad enum variant for ty::UnsizeKind")
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/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs
index 09490f9bdf7..9900620b229 100644
--- a/src/librustc/middle/traits/coherence.rs
+++ b/src/librustc/middle/traits/coherence.rs
@@ -143,7 +143,7 @@ pub fn ty_is_local(tcx: &ty::ctxt,
         }
 
         ty::ty_trait(ref tt) => {
-            tt.def_id.krate == ast::LOCAL_CRATE
+            tt.principal.def_id.krate == ast::LOCAL_CRATE
         }
 
         // Type parameters may be bound to types that are not local to
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 8309811cf0b..5b2e978e11f 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -423,8 +423,8 @@ impl TypeMap {
 
                 from_def_id_and_substs(self,
                                        cx,
-                                       trait_data.def_id,
-                                       &trait_data.substs,
+                                       trait_data.principal.def_id,
+                                       &trait_data.principal.substs,
                                        &mut unique_type_id);
             },
             ty::ty_bare_fn(ty::BareFnTy{ fn_style, abi, ref sig } ) => {
@@ -2813,7 +2813,7 @@ fn trait_pointer_metadata(cx: &CrateContext,
     // But it does not describe the trait's methods.
 
     let def_id = match ty::get(trait_type).sty {
-        ty::ty_trait(box ty::TyTrait { def_id, .. }) => def_id,
+        ty::ty_trait(box ty::TyTrait { ref principal, .. }) => principal.def_id,
         _ => {
             let pp_type_name = ppaux::ty_to_string(cx.tcx(), trait_type);
             cx.sess().bug(format!("debuginfo: Unexpected trait-object type in \
@@ -3739,8 +3739,8 @@ fn push_debuginfo_type_name(cx: &CrateContext,
             output.push(']');
         },
         ty::ty_trait(ref trait_data) => {
-            push_item_name(cx, trait_data.def_id, false, output);
-            push_type_params(cx, &trait_data.substs, output);
+            push_item_name(cx, trait_data.principal.def_id, false, output);
+            push_type_params(cx, &trait_data.principal.substs, output);
         },
         ty::ty_bare_fn(ty::BareFnTy{ fn_style, abi, ref sig } ) => {
             if fn_style == ast::UnsafeFn {
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 399be73329b..4b61f0c1409 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -324,10 +324,10 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 _ => bcx.sess().bug(format!("UnsizeStruct with bad sty: {}",
                                           bcx.ty_to_string(unsized_ty)).as_slice())
             },
-            &ty::UnsizeVtable(ty::TyTrait { def_id, ref substs, .. }, _) => {
-                let substs = substs.with_self_ty(unsized_ty);
+            &ty::UnsizeVtable(ty::TyTrait { ref principal, .. }, _) => {
+                let substs = principal.substs.with_self_ty(unsized_ty);
                 let trait_ref =
-                    Rc::new(ty::TraitRef { def_id: def_id,
+                    Rc::new(ty::TraitRef { def_id: principal.def_id,
                                            substs: substs });
                 let trait_ref =
                     trait_ref.subst(bcx.tcx(), &bcx.fcx.param_substs.substs);
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index d1baeac81ab..1a6e8eeb320 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -378,14 +378,14 @@ pub fn type_of_adjust(cx: &ctxt, adj: &AutoAdjustment) -> Option<t> {
     fn type_of_autoref(cx: &ctxt, autoref: &AutoRef) -> Option<t> {
         match autoref {
             &AutoUnsize(ref k) => match k {
-                &UnsizeVtable(TyTrait { def_id, ref substs, bounds }, _) => {
-                    Some(mk_trait(cx, def_id, substs.clone(), bounds))
+                &UnsizeVtable(TyTrait { ref principal, bounds }, _) => {
+                    Some(mk_trait(cx, (*principal).clone(), bounds))
                 }
                 _ => None
             },
             &AutoUnsizeUniq(ref k) => match k {
-                &UnsizeVtable(TyTrait { def_id, ref substs, bounds }, _) => {
-                    Some(mk_uniq(cx, mk_trait(cx, def_id, substs.clone(), bounds)))
+                &UnsizeVtable(TyTrait { ref principal, bounds }, _) => {
+                    Some(mk_uniq(cx, mk_trait(cx, (*principal).clone(), bounds)))
                 }
                 _ => None
             },
@@ -983,12 +983,12 @@ pub enum sty {
 
 #[deriving(Clone, PartialEq, Eq, Hash, Show)]
 pub struct TyTrait {
-    pub def_id: DefId,
-    pub substs: Substs,
+    // Principal trait reference.
+    pub principal: TraitRef, // would use Rc<TraitRef>, but it runs afoul of some static rules
     pub bounds: ExistentialBounds
 }
 
-#[deriving(PartialEq, Eq, Hash, Show)]
+#[deriving(Clone, PartialEq, Eq, Hash, Show)]
 pub struct TraitRef {
     pub def_id: DefId,
     pub substs: Substs,
@@ -1643,8 +1643,8 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
       &ty_enum(_, ref substs) | &ty_struct(_, ref substs) => {
           flags = flags | sflags(substs);
       }
-      &ty_trait(box TyTrait { ref substs, ref bounds, .. }) => {
-          flags = flags | sflags(substs);
+      &ty_trait(box TyTrait { ref principal, ref bounds }) => {
+          flags = flags | sflags(&principal.substs);
           flags = flags | flags_for_bounds(bounds);
       }
       &ty_uniq(tt) | &ty_vec(tt, _) | &ty_open(tt) => {
@@ -1874,14 +1874,12 @@ pub fn mk_ctor_fn(cx: &ctxt,
 
 
 pub fn mk_trait(cx: &ctxt,
-                did: ast::DefId,
-                substs: Substs,
+                principal: ty::TraitRef,
                 bounds: ExistentialBounds)
                 -> t {
     // take a copy of substs so that we own the vectors inside
     let inner = box TyTrait {
-        def_id: did,
-        substs: substs,
+        principal: principal,
         bounds: bounds
     };
     mk_t(cx, ty_trait(inner))
@@ -1934,9 +1932,15 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) {
         ty_ptr(ref tm) | ty_rptr(_, ref tm) => {
             maybe_walk_ty(tm.ty, f);
         }
-        ty_enum(_, ref substs) | ty_struct(_, ref substs) | ty_unboxed_closure(_, _, ref substs) |
-        ty_trait(box TyTrait { ref substs, .. }) => {
-            for subty in (*substs).types.iter() {
+        ty_trait(box TyTrait { ref principal, .. }) => {
+            for subty in principal.substs.types.iter() {
+                maybe_walk_ty(*subty, |x| f(x));
+            }
+        }
+        ty_enum(_, ref substs) |
+        ty_struct(_, ref substs) |
+        ty_unboxed_closure(_, _, ref substs) => {
+            for subty in substs.types.iter() {
                 maybe_walk_ty(*subty, |x| f(x));
             }
         }
@@ -3554,8 +3558,8 @@ pub fn unsize_ty(cx: &ctxt,
                                   format!("UnsizeStruct with bad sty: {}",
                                           ty_to_string(cx, ty)).as_slice())
         },
-        &UnsizeVtable(TyTrait { def_id, ref substs, bounds }, _) => {
-            mk_trait(cx, def_id, substs.clone(), bounds)
+        &UnsizeVtable(TyTrait { ref principal, bounds }, _) => {
+            mk_trait(cx, (*principal).clone(), bounds)
         }
     }
 }
@@ -3808,7 +3812,7 @@ pub fn ty_sort_string(cx: &ctxt, t: t) -> String {
         ty_bare_fn(_) => "extern fn".to_string(),
         ty_closure(_) => "fn".to_string(),
         ty_trait(ref inner) => {
-            format!("trait {}", item_path_str(cx, inner.def_id))
+            format!("trait {}", item_path_str(cx, inner.principal.def_id))
         }
         ty_struct(id, _) => {
             format!("struct {}", item_path_str(cx, id))
@@ -4230,11 +4234,14 @@ pub fn try_add_builtin_trait(
 
 pub fn ty_to_def_id(ty: t) -> Option<ast::DefId> {
     match get(ty).sty {
-        ty_trait(box TyTrait { def_id: id, .. }) |
+        ty_trait(ref tt) =>
+            Some(tt.principal.def_id),
         ty_struct(id, _) |
         ty_enum(id, _) |
-        ty_unboxed_closure(id, _, _) => Some(id),
-        _ => None
+        ty_unboxed_closure(id, _, _) =>
+            Some(id),
+        _ =>
+            None
     }
 }
 
@@ -5213,9 +5220,9 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 {
                     }
                 }
             }
-            ty_trait(box TyTrait { def_id: d, bounds, .. }) => {
+            ty_trait(box TyTrait { ref principal, bounds }) => {
                 byte!(17);
-                did(&mut state, d);
+                did(&mut state, principal.def_id);
                 hash!(bounds);
             }
             ty_struct(d, _) => {
@@ -5504,12 +5511,13 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
                                     typ: t) {
     walk_ty(typ, |typ| {
         match get(typ).sty {
-            ty_rptr(region, _) => accumulator.push(region),
+            ty_rptr(region, _) => {
+                accumulator.push(region)
+            }
+            ty_trait(ref t) => {
+                accumulator.push_all(t.principal.substs.regions().as_slice());
+            }
             ty_enum(_, ref substs) |
-            ty_trait(box TyTrait {
-                ref substs,
-                ..
-            }) |
             ty_struct(_, ref substs) => {
                 accum_substs(accumulator, substs);
             }
@@ -5538,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/ty_fold.rs b/src/librustc/middle/ty_fold.rs
index 6a72574aaaa..031c7b2aed6 100644
--- a/src/librustc/middle/ty_fold.rs
+++ b/src/librustc/middle/ty_fold.rs
@@ -373,12 +373,11 @@ impl TypeFoldable for ty::UnsizeKind {
         match *self {
             ty::UnsizeLength(len) => ty::UnsizeLength(len),
             ty::UnsizeStruct(box ref k, n) => ty::UnsizeStruct(box k.fold_with(folder), n),
-            ty::UnsizeVtable(ty::TyTrait{bounds, def_id, ref substs}, self_ty) => {
+            ty::UnsizeVtable(ty::TyTrait{ref principal, bounds}, self_ty) => {
                 ty::UnsizeVtable(
                     ty::TyTrait {
+                        principal: principal.fold_with(folder),
                         bounds: bounds.fold_with(folder),
-                        def_id: def_id,
-                        substs: substs.fold_with(folder)
                     },
                     self_ty.fold_with(folder))
             }
@@ -531,15 +530,10 @@ pub fn super_fold_sty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
         ty::ty_enum(tid, ref substs) => {
             ty::ty_enum(tid, substs.fold_with(this))
         }
-        ty::ty_trait(box ty::TyTrait {
-                def_id,
-                ref substs,
-                bounds
-            }) => {
+        ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => {
             ty::ty_trait(box ty::TyTrait {
-                def_id: def_id,
-                substs: substs.fold_with(this),
-                bounds: this.fold_existential_bounds(bounds),
+                principal: (*principal).fold_with(this),
+                bounds: bounds.fold_with(this),
             })
         }
         ty::ty_tup(ref ts) => {
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index ae0bbd617e2..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,
@@ -405,11 +443,11 @@ pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC,
                                          associated_type: Option<ty::t>,
                                          path: &ast::Path,
                                          binder_id: ast::NodeId)
-                                         -> Rc<ty::TraitRef>
+                                         -> ty::TraitRef
                                          where AC: AstConv<'tcx>,
                                                RS: RegionScope {
     let trait_def = this.get_trait_def(trait_def_id);
-    Rc::new(ty::TraitRef {
+    ty::TraitRef {
         def_id: trait_def_id,
         substs: ast_path_substs(this,
                                 rscope,
@@ -419,7 +457,7 @@ pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC,
                                 associated_type,
                                 path,
                                 binder_id)
-    })
+    }
 }
 
 pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
@@ -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.
@@ -702,26 +705,17 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
                                                        None,
                                                        path,
                                                        id);
-                    let bounds = match *opt_bounds {
-                        None => {
-                            conv_existential_bounds(this,
-                                                    rscope,
-                                                    path.span,
-                                                    [result.clone()].as_slice(),
-                                                    [].as_slice())
-                        }
-                        Some(ref bounds) => {
-                            conv_existential_bounds(this,
-                                                    rscope,
-                                                    path.span,
-                                                    [result.clone()].as_slice(),
-                                                    bounds.as_slice())
-                        }
-                    };
+                    let empty_vec = [];
+                    let bounds = match *opt_bounds { None => empty_vec.as_slice(),
+                                                     Some(ref bounds) => bounds.as_slice() };
+                    let existential_bounds = conv_existential_bounds(this,
+                                                                     rscope,
+                                                                     path.span,
+                                                                     &[Rc::new(result.clone())],
+                                                                     bounds);
                     let tr = ty::mk_trait(tcx,
-                                          result.def_id,
-                                          result.substs.clone(),
-                                          bounds);
+                                          result,
+                                          existential_bounds);
                     return match ptr_ty {
                         Uniq => {
                             return ty::mk_uniq(tcx, tr);
@@ -907,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 => {
@@ -943,11 +947,10 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
                         let bounds = conv_existential_bounds(this,
                                                              rscope,
                                                              ast_ty.span,
-                                                             &[result.clone()],
+                                                             &[Rc::new(result.clone())],
                                                              ast_bounds);
                         ty::mk_trait(tcx,
-                                     result.def_id,
-                                     result.substs.clone(),
+                                     result,
                                      bounds)
                     }
                     def::DefTy(did, _) | def::DefStruct(did) => {
@@ -1546,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/check/method.rs b/src/librustc/middle/typeck/check/method.rs
index ef616a4a07a..6280fce035a 100644
--- a/src/librustc/middle/typeck/check/method.rs
+++ b/src/librustc/middle/typeck/check/method.rs
@@ -632,9 +632,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
         let span = self.self_expr.map_or(self.span, |e| e.span);
         check::autoderef(self.fcx, span, self_ty, None, NoPreference, |self_ty, _| {
             match get(self_ty).sty {
-                ty_trait(box TyTrait { def_id, ref substs, bounds, .. }) => {
-                    self.push_inherent_candidates_from_object(self_ty, def_id, substs, bounds);
-                    self.push_inherent_impl_candidates_for_type(def_id);
+                ty_trait(box TyTrait { ref principal, bounds, .. }) => {
+                    self.push_inherent_candidates_from_object(self_ty, &*principal, bounds);
+                    self.push_inherent_impl_candidates_for_type(principal.def_id);
                 }
                 ty_enum(did, _) |
                 ty_struct(did, _) |
@@ -744,24 +744,23 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
 
     fn push_inherent_candidates_from_object(&mut self,
                                             self_ty: ty::t,
-                                            did: DefId,
-                                            substs: &subst::Substs,
+                                            principal: &ty::TraitRef,
                                             _bounds: ty::ExistentialBounds) {
         debug!("push_inherent_candidates_from_object(self_ty={})",
                self_ty.repr(self.tcx()));
 
         let tcx = self.tcx();
 
-        // It is illegal to invoke a method on a trait instance that refers to
-        // the `Self` type.  Here, we use a substitution that replaces `Self`
-        // with the object type itself. Hence, a `&self` method will wind up
-        // with an argument type like `&Trait`.
-        let rcvr_substs = substs.with_self_ty(self_ty);
-
-        let trait_ref = Rc::new(TraitRef {
-            def_id: did,
-            substs: rcvr_substs.clone()
-        });
+        // It is illegal to invoke a method on a trait instance that
+        // refers to the `Self` type. An error will be reported by
+        // `enforce_object_limitations()` if the method refers to the
+        // `Self` type anywhere other than the receiver. Here, we use
+        // a substitution that replaces `Self` with the object type
+        // itself. Hence, a `&self` method will wind up with an
+        // argument type like `&Trait`.
+        let rcvr_substs = principal.substs.with_self_ty(self_ty);
+        let trait_ref = Rc::new(TraitRef { def_id: principal.def_id,
+                                           substs: rcvr_substs.clone() });
 
         self.push_inherent_candidates_from_bounds_inner(
             &[trait_ref.clone()],
@@ -796,7 +795,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
                     method_ty: m,
                     origin: MethodTraitObject(MethodObject {
                         trait_ref: new_trait_ref,
-                        object_trait_id: did,
+                        object_trait_id: principal.def_id,
                         method_num: method_num,
                         real_index: vtable_index
                     })
@@ -1151,17 +1150,19 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
     fn auto_slice_trait(&self, ty: ty::t, autoderefs: uint) -> Option<MethodResult> {
         debug!("auto_slice_trait");
         match ty::get(ty).sty {
-            ty_trait(box ty::TyTrait {
-                    def_id: trt_did,
-                    substs: ref trt_substs,
-                    bounds: b,
-                    .. }) => {
+            ty_trait(box ty::TyTrait { ref principal,
+                                       bounds: b,
+                                       .. }) => {
+                let trt_did = principal.def_id;
+                let trt_substs = &principal.substs;
                 let tcx = self.tcx();
                 self.search_for_some_kind_of_autorefd_method(
                     |r, m| AutoPtr(r, m, None),
                     autoderefs, [MutImmutable, MutMutable],
                     |m, r| {
-                        let tr = ty::mk_trait(tcx, trt_did, trt_substs.clone(), b);
+                        let principal = ty::TraitRef::new(trt_did,
+                                                          trt_substs.clone());
+                        let tr = ty::mk_trait(tcx, principal, b);
                         ty::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: m })
                     })
             }
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index 2fcce4cc3dc..498594716e7 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -140,11 +140,11 @@ pub fn check_object_safety(tcx: &ty::ctxt, object_trait: &ty::TyTrait, span: Spa
     // `call_once` which is the method which takes self by value. What could go
     // wrong?
     match tcx.lang_items.fn_once_trait() {
-        Some(def_id) if def_id == object_trait.def_id => return,
+        Some(def_id) if def_id == object_trait.principal.def_id => return,
         _ => {}
     }
 
-    let trait_items = ty::trait_items(tcx, object_trait.def_id);
+    let trait_items = ty::trait_items(tcx, object_trait.principal.def_id);
 
     let mut errors = Vec::new();
     for item in trait_items.iter() {
@@ -158,7 +158,7 @@ pub fn check_object_safety(tcx: &ty::ctxt, object_trait: &ty::TyTrait, span: Spa
 
     let mut errors = errors.iter().flat_map(|x| x.iter()).peekable();
     if errors.peek().is_some() {
-        let trait_name = ty::item_path_str(tcx, object_trait.def_id);
+        let trait_name = ty::item_path_str(tcx, object_trait.principal.def_id);
         span_err!(tcx.sess, span, E0038,
             "cannot convert to a trait object because trait `{}` is not object-safe",
             trait_name);
@@ -241,8 +241,7 @@ pub fn register_object_cast_obligations(fcx: &FnCtxt,
     // needs some refactoring so there is a more convenient type to pass around.
     let object_trait_ty =
         ty::mk_trait(fcx.tcx(),
-                     object_trait.def_id,
-                     object_trait.substs.clone(),
+                     object_trait.principal.clone(),
                      object_trait.bounds);
 
     debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}",
@@ -252,13 +251,13 @@ pub fn register_object_cast_obligations(fcx: &FnCtxt,
     // Take the type parameters from the object type, but set
     // the Self type (which is unknown, for the object type)
     // to be the type we are casting from.
-    let mut object_substs = object_trait.substs.clone();
+    let mut object_substs = object_trait.principal.substs.clone();
     assert!(object_substs.self_ty().is_none());
     object_substs.types.push(SelfSpace, referent_ty);
 
     // Create the obligation for casting from T to Trait.
     let object_trait_ref =
-        Rc::new(ty::TraitRef { def_id: object_trait.def_id,
+        Rc::new(ty::TraitRef { def_id: object_trait.principal.def_id,
                                substs: object_substs });
     let object_obligation =
         Obligation::new(
diff --git a/src/librustc/middle/typeck/coherence/mod.rs b/src/librustc/middle/typeck/coherence/mod.rs
index 19ff82469b5..898d987ace7 100644
--- a/src/librustc/middle/typeck/coherence/mod.rs
+++ b/src/librustc/middle/typeck/coherence/mod.rs
@@ -112,8 +112,8 @@ fn get_base_type_def_id(inference_context: &InferCtxt,
                 ty_rptr(_, ty::mt {ty, ..}) |
                 ty_uniq(ty) => {
                     match ty::get(ty).sty {
-                        ty_trait(box ty::TyTrait { def_id, .. }) => {
-                            Some(def_id)
+                        ty_trait(box ty::TyTrait { ref principal, .. }) => {
+                            Some(principal.def_id)
                         }
                         _ => {
                             panic!("get_base_type() returned a type that wasn't an \
@@ -121,8 +121,8 @@ fn get_base_type_def_id(inference_context: &InferCtxt,
                         }
                     }
                 }
-                ty_trait(box ty::TyTrait { def_id, .. }) => {
-                    Some(def_id)
+                ty_trait(box ty::TyTrait { ref principal, .. }) => {
+                    Some(principal.def_id)
                 }
                 _ => {
                     panic!("get_base_type() returned a type that wasn't an \
diff --git a/src/librustc/middle/typeck/coherence/orphan.rs b/src/librustc/middle/typeck/coherence/orphan.rs
index 3c4ad347361..ba362fb878c 100644
--- a/src/librustc/middle/typeck/coherence/orphan.rs
+++ b/src/librustc/middle/typeck/coherence/orphan.rs
@@ -18,6 +18,7 @@ use middle::ty;
 use syntax::ast::{Item, ItemImpl};
 use syntax::ast;
 use syntax::ast_util;
+use syntax::codemap::Span;
 use syntax::visit;
 use util::ppaux::Repr;
 
@@ -30,6 +31,17 @@ struct OrphanChecker<'cx, 'tcx:'cx> {
     tcx: &'cx ty::ctxt<'tcx>
 }
 
+impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
+    fn check_def_id(&self, span: Span, def_id: ast::DefId) {
+        if def_id.krate != ast::LOCAL_CRATE {
+            span_err!(self.tcx.sess, span, E0116,
+                      "cannot associate methods with a type outside the \
+                       crate the type is defined in; define and implement \
+                       a trait or new type instead");
+        }
+    }
+}
+
 impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &'v ast::Item) {
         let def_id = ast_util::local_def(item.id);
@@ -41,14 +53,11 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
                 let self_ty = ty::lookup_item_type(self.tcx, def_id).ty;
                 match ty::get(self_ty).sty {
                     ty::ty_enum(def_id, _) |
-                    ty::ty_struct(def_id, _) |
-                    ty::ty_trait(box ty::TyTrait{ def_id, ..}) => {
-                        if def_id.krate != ast::LOCAL_CRATE {
-                            span_err!(self.tcx.sess, item.span, E0116,
-                                      "cannot associate methods with a type outside the \
-                                      crate the type is defined in; define and implement \
-                                      a trait or new type instead");
-                        }
+                    ty::ty_struct(def_id, _) => {
+                        self.check_def_id(item.span, def_id);
+                    }
+                    ty::ty_trait(box ty::TyTrait{ ref principal, ..}) => {
+                        self.check_def_id(item.span, principal.def_id);
                     }
                     _ => {
                         span_err!(self.tcx.sess, item.span, E0118,
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index ae2073f6316..c4e50c25e3e 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,8 @@ 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 +1324,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 =
-                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 +1688,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 +1720,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 +1838,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 +1940,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 +2015,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/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs
index e44aa3e8221..718d70050a0 100644
--- a/src/librustc/middle/typeck/infer/coercion.rs
+++ b/src/librustc/middle/typeck/infer/coercion.rs
@@ -413,15 +413,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                     let ty = ty::mk_vec(tcx, t_a, None);
                     Some((ty, ty::UnsizeLength(len)))
                 }
-                (&ty::ty_trait(..), &ty::ty_trait(..)) => None,
-                (_, &ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds })) => {
-                    let ty = ty::mk_trait(tcx,
-                                          def_id,
-                                          substs.clone(),
-                                          bounds);
-                    Some((ty, ty::UnsizeVtable(ty::TyTrait { def_id: def_id,
-                                                             bounds: bounds,
-                                                             substs: substs.clone() },
+                (&ty::ty_trait(..), &ty::ty_trait(..)) => {
+                    None
+                }
+                (_, &ty::ty_trait(box ty::TyTrait { ref principal, bounds })) => {
+                    // FIXME what is the purpose of `ty`?
+                    let ty = ty::mk_trait(tcx, (*principal).clone(), bounds);
+                    Some((ty, ty::UnsizeVtable(ty::TyTrait { principal: (*principal).clone(),
+                                                             bounds: bounds },
                                                ty_a)))
                 }
                 (&ty::ty_struct(did_a, ref substs_a), &ty::ty_struct(did_b, ref substs_b))
@@ -524,16 +523,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
         match *sty_a {
             ty::ty_rptr(_, ty::mt{ty, mutbl}) => match ty::get(ty).sty {
-                ty::ty_trait(box ty::TyTrait {
-                        def_id,
-                        ref substs,
-                        bounds,
-                        ..
-                    }) =>
-                {
+                ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => {
                     debug!("mutbl={} b_mutbl={}", mutbl, b_mutbl);
-
-                    let tr = ty::mk_trait(tcx, def_id, substs.clone(), bounds);
+                    // FIXME what is purpose of this type `tr`?
+                    let tr = ty::mk_trait(tcx, (*principal).clone(), bounds);
                     try!(self.subtype(mk_ty(tr), b));
                     Ok(Some(AdjustDerefRef(AutoDerefRef {
                         autoderefs: 1,
diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs
index e51eb331cdc..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;
@@ -461,15 +460,11 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<t
       }
 
       (&ty::ty_trait(ref a_),
-       &ty::ty_trait(ref b_))
-      if a_.def_id == b_.def_id => {
+       &ty::ty_trait(ref b_)) => {
           debug!("Trying to match traits {} and {}", a, b);
-          let substs = try!(this.substs(a_.def_id, &a_.substs, &b_.substs));
+          let principal = try!(this.trait_refs(&a_.principal, &b_.principal));
           let bounds = try!(this.existential_bounds(a_.bounds, b_.bounds));
-          Ok(ty::mk_trait(tcx,
-                          a_.def_id,
-                          substs.clone(),
-                          bounds))
+          Ok(ty::mk_trait(tcx, principal, bounds))
       }
 
       (&ty::ty_struct(a_id, ref a_substs), &ty::ty_struct(b_id, ref b_substs))
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/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs
index 55c3c236853..23000949115 100644
--- a/src/librustc/middle/typeck/infer/mod.rs
+++ b/src/librustc/middle/typeck/infer/mod.rs
@@ -856,16 +856,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                                       -> ty::TraitRef {
         // make up a dummy type just to reuse/abuse the resolve machinery
         let dummy0 = ty::mk_trait(self.tcx,
-                                  trait_ref.def_id,
-                                  trait_ref.substs.clone(),
+                                  (*trait_ref).clone(),
                                   ty::region_existential_bound(ty::ReStatic));
         let dummy1 = self.resolve_type_vars_if_possible(dummy0);
         match ty::get(dummy1).sty {
-            ty::ty_trait(box ty::TyTrait { ref def_id, ref substs, .. }) => {
-                ty::TraitRef {
-                    def_id: *def_id,
-                    substs: (*substs).clone(),
-                }
+            ty::ty_trait(box ty::TyTrait { ref principal, .. }) => {
+                (*principal).clone()
             }
             _ => {
                 self.tcx.sess.bug(
diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs
index 4227cc521b4..b6d8c85fa0b 100644
--- a/src/librustc/middle/typeck/variance.rs
+++ b/src/librustc/middle/typeck/variance.rs
@@ -778,14 +778,14 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                     variance);
             }
 
-            ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds }) => {
-                let trait_def = ty::lookup_trait_def(self.tcx(), def_id);
+            ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => {
+                let trait_def = ty::lookup_trait_def(self.tcx(), principal.def_id);
                 let generics = &trait_def.generics;
 
                 // Traits DO have a Self type parameter, but it is
                 // erased from object types.
                 assert!(!generics.types.is_empty_in(subst::SelfSpace) &&
-                        substs.types.is_empty_in(subst::SelfSpace));
+                        principal.substs.types.is_empty_in(subst::SelfSpace));
 
                 // Traits never declare region parameters in the self
                 // space.
@@ -801,10 +801,10 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 self.add_constraints_from_region(bounds.region_bound, contra);
 
                 self.add_constraints_from_substs(
-                    def_id,
+                    principal.def_id,
                     generics.types.get_slice(subst::TypeSpace),
                     generics.regions.get_slice(subst::TypeSpace),
-                    substs,
+                    &principal.substs,
                     variance);
             }
 
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 9080b12c543..60a7436dbaa 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -435,12 +435,12 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
             parameterized(cx, base.as_slice(), substs, &generics)
         }
         ty_trait(box ty::TyTrait {
-            def_id: did, ref substs, ref bounds
+            ref principal, ref bounds
         }) => {
-            let base = ty::item_path_str(cx, did);
-            let trait_def = ty::lookup_trait_def(cx, did);
+            let base = ty::item_path_str(cx, principal.def_id);
+            let trait_def = ty::lookup_trait_def(cx, principal.def_id);
             let ty = parameterized(cx, base.as_slice(),
-                                   substs, &trait_def.generics);
+                                   &principal.substs, &trait_def.generics);
             let bound_str = bounds.user_string(cx);
             let bound_sep = if bound_str.is_empty() { "" } else { "+" };
             format!("{}{}{}",
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/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 80b158a54d3..c38fea9b3d5 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -38,7 +38,6 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
     ("globs", Active),
     ("macro_rules", Active),
     ("struct_variant", Active),
-    ("once_fns", Active),
     ("asm", Active),
     ("managed_boxes", Removed),
     ("non_ascii_idents", Active),
@@ -307,11 +306,10 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {
 
     fn visit_ty(&mut self, t: &ast::Ty) {
         match t.node {
-            ast::TyClosure(ref closure) if closure.onceness == ast::Once => {
-                self.gate_feature("once_fns", t.span,
-                                  "once functions are \
-                                   experimental and likely to be removed");
-
+            ast::TyClosure(ref closure) => {
+                // this used to be blocked by a feature gate, but it should just
+                // be plain impossible right now
+                assert!(closure.onceness != ast::Once);
             },
             _ => {}
         }
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index d977f2b99cc..d7c3ca8efc4 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/parse/token.rs b/src/libsyntax/parse/token.rs
index b0cca5e14de..f501a5831d2 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -503,42 +503,41 @@ declare_special_idents_and_keywords! {
         (27,                         Mod,        "mod");
         (28,                         Move,       "move");
         (29,                         Mut,        "mut");
-        (30,                         Once,       "once");
-        (31,                         Pub,        "pub");
-        (32,                         Ref,        "ref");
-        (33,                         Return,     "return");
+        (30,                         Pub,        "pub");
+        (31,                         Ref,        "ref");
+        (32,                         Return,     "return");
         // Static and Self are also special idents (prefill de-dupes)
         (super::STATIC_KEYWORD_NAME_NUM, Static, "static");
         (super::SELF_KEYWORD_NAME_NUM,   Self,   "self");
-        (34,                         Struct,     "struct");
+        (33,                         Struct,     "struct");
         (super::SUPER_KEYWORD_NAME_NUM, Super,   "super");
-        (35,                         True,       "true");
-        (36,                         Trait,      "trait");
-        (37,                         Type,       "type");
-        (38,                         Unsafe,     "unsafe");
-        (39,                         Use,        "use");
-        (40,                         Virtual,    "virtual");
-        (41,                         While,      "while");
-        (42,                         Continue,   "continue");
-        (43,                         Proc,       "proc");
-        (44,                         Box,        "box");
-        (45,                         Const,      "const");
-        (46,                         Where,      "where");
+        (34,                         True,       "true");
+        (35,                         Trait,      "trait");
+        (36,                         Type,       "type");
+        (37,                         Unsafe,     "unsafe");
+        (38,                         Use,        "use");
+        (39,                         Virtual,    "virtual");
+        (40,                         While,      "while");
+        (41,                         Continue,   "continue");
+        (42,                         Proc,       "proc");
+        (43,                         Box,        "box");
+        (44,                         Const,      "const");
+        (45,                         Where,      "where");
 
         'reserved:
-        (47,                         Alignof,    "alignof");
-        (48,                         Be,         "be");
-        (49,                         Offsetof,   "offsetof");
-        (50,                         Priv,       "priv");
-        (51,                         Pure,       "pure");
-        (52,                         Sizeof,     "sizeof");
-        (53,                         Typeof,     "typeof");
-        (54,                         Unsized,    "unsized");
-        (55,                         Yield,      "yield");
-        (56,                         Do,         "do");
-        (57,                         Abstract,   "abstract");
-        (58,                         Final,      "final");
-        (59,                         Override,   "override");
+        (46,                         Alignof,    "alignof");
+        (47,                         Be,         "be");
+        (48,                         Offsetof,   "offsetof");
+        (49,                         Priv,       "priv");
+        (50,                         Pure,       "pure");
+        (51,                         Sizeof,     "sizeof");
+        (52,                         Typeof,     "typeof");
+        (53,                         Unsized,    "unsized");
+        (54,                         Yield,      "yield");
+        (55,                         Do,         "do");
+        (56,                         Abstract,   "abstract");
+        (57,                         Final,      "final");
+        (58,                         Override,   "override");
     }
 }
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 63e2c5499e8..c1515a36bec 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("?"));
             }
@@ -2658,12 +2663,10 @@ impl<'a> State<'a> {
         } else if opt_sigil == Some('&') {
             try!(self.print_fn_style(fn_style));
             try!(self.print_extern_opt_abi(opt_abi));
-            try!(self.print_onceness(onceness));
         } else {
             assert!(opt_sigil.is_none());
             try!(self.print_fn_style(fn_style));
             try!(self.print_opt_abi_and_extern_if_nondefault(opt_abi));
-            try!(self.print_onceness(onceness));
             try!(word(&mut self.s, "fn"));
         }
 
@@ -2982,13 +2985,6 @@ impl<'a> State<'a> {
             ast::UnsafeFn => self.word_nbsp("unsafe"),
         }
     }
-
-    pub fn print_onceness(&mut self, o: ast::Onceness) -> IoResult<()> {
-        match o {
-            ast::Once => self.word_nbsp("once"),
-            ast::Many => Ok(())
-        }
-    }
 }
 
 #[cfg(test)]
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/once-cant-call-twice-on-stack.rs b/src/test/compile-fail/once-cant-call-twice-on-stack.rs
deleted file mode 100644
index 17968195280..00000000000
--- a/src/test/compile-fail/once-cant-call-twice-on-stack.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2013 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.
-
-// Testing guarantees provided by once functions.
-// This program would segfault if it were legal.
-
-#![feature(once_fns)]
-use std::sync::Arc;
-
-fn foo(blk: once ||) {
-    blk();
-    blk(); //~ ERROR use of moved value
-}
-
-fn main() {
-    let x = Arc::new(true);
-    foo(|| {
-        assert!(*x);
-        drop(x);
-    })
-}
diff --git a/src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs b/src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs
deleted file mode 100644
index 3efebf61844..00000000000
--- a/src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2013 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.
-
-// Testing guarantees provided by once functions.
-// This program would segfault if it were legal.
-
-use std::sync::Arc;
-
-fn foo(blk: ||) {
-    blk();
-    blk();
-}
-
-fn main() {
-    let x = Arc::new(true);
-    foo(|| {
-        assert!(*x);
-        drop(x); //~ ERROR cannot move out of captured outer variable
-    })
-}
diff --git a/src/test/compile-fail/once-fn-subtyping.rs b/src/test/compile-fail/once-fn-subtyping.rs
deleted file mode 100644
index 7594deda3b2..00000000000
--- a/src/test/compile-fail/once-fn-subtyping.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2012-2013 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.
-
-#![feature(once_fns)]
-fn main() {
-    let f: once || = ||();
-    let g: || = f;  //~ ERROR mismatched types
-    let h: || = ||();
-    let i: once || = h;  // ok
-}
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-duplicated.rs b/src/test/compile-fail/regions-name-duplicated.rs
index 58eaa4c57fe..518fe0b00b6 100644
--- a/src/test/compile-fail/regions-name-duplicated.rs
+++ b/src/test/compile-fail/regions-name-duplicated.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 struct Foo<'a, 'a> { //~ ERROR lifetime name `'a` declared twice
-//~^ ERROR lifetime name `'a` declared twice
     x: &'a int
 }
 
diff --git a/src/test/compile-fail/regions-name-static.rs b/src/test/compile-fail/regions-name-static.rs
index bc8ca87d7e2..9f50ad36660 100644
--- a/src/test/compile-fail/regions-name-static.rs
+++ b/src/test/compile-fail/regions-name-static.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 struct Foo<'static> { //~ ERROR illegal lifetime parameter name: `'static`
-//~^ ERROR illegal lifetime parameter name: `'static`
     x: &'static int
 }
 
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);
     }
 }
diff --git a/src/test/run-pass/once-move-out-on-heap.rs b/src/test/run-pass/once-move-out-on-heap.rs
index dfd5992a406..e24e809ed01 100644
--- a/src/test/run-pass/once-move-out-on-heap.rs
+++ b/src/test/run-pass/once-move-out-on-heap.rs
@@ -11,7 +11,6 @@
 // Testing guarantees provided by once functions.
 
 
-#![feature(once_fns)]
 use std::sync::Arc;
 
 fn foo(blk: proc()) {
diff --git a/src/test/run-pass/once-move-out-on-stack.rs b/src/test/run-pass/once-move-out-on-stack.rs
deleted file mode 100644
index 0419fc54add..00000000000
--- a/src/test/run-pass/once-move-out-on-stack.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2013-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.
-
-// Testing guarantees provided by once functions.
-
-
-#![feature(once_fns)]
-use std::sync::Arc;
-
-fn foo(blk: once ||) {
-    blk();
-}
-
-pub fn main() {
-    let x = Arc::new(true);
-    foo(|| {
-        assert!(*x);
-        drop(x);
-    })
-}