about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/metadata/encoder.rs3
-rw-r--r--src/librustc/metadata/tydecode.rs3
-rw-r--r--src/librustc/metadata/tyencode.rs5
-rw-r--r--src/librustc/middle/kind.rs8
-rw-r--r--src/librustc/middle/lint.rs2
-rw-r--r--src/librustc/middle/region.rs4
-rw-r--r--src/librustc/middle/resolve.rs8
-rw-r--r--src/librustc/middle/trans/debuginfo.rs2
-rw-r--r--src/librustc/middle/trans/expr.rs2
-rw-r--r--src/librustc/middle/trans/glue.rs8
-rw-r--r--src/librustc/middle/trans/monomorphize.rs2
-rw-r--r--src/librustc/middle/trans/reachable.rs2
-rw-r--r--src/librustc/middle/trans/reflect.rs2
-rw-r--r--src/librustc/middle/trans/type_of.rs4
-rw-r--r--src/librustc/middle/trans/type_use.rs2
-rw-r--r--src/librustc/middle/ty.rs48
-rw-r--r--src/librustc/middle/typeck/astconv.rs20
-rw-r--r--src/librustc/middle/typeck/check/method.rs2
-rw-r--r--src/librustc/middle/typeck/check/regionck.rs2
-rw-r--r--src/librustc/middle/typeck/check/vtable.rs9
-rw-r--r--src/librustc/middle/typeck/coherence.rs6
-rw-r--r--src/librustc/middle/typeck/infer/combine.rs8
-rw-r--r--src/librustc/middle/typeck/infer/mod.rs5
-rw-r--r--src/librustc/util/ppaux.rs8
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/ast_util.rs2
-rw-r--r--src/libsyntax/ext/build.rs16
-rw-r--r--src/libsyntax/ext/deriving/generic.rs3
-rw-r--r--src/libsyntax/ext/deriving/ty.rs5
-rw-r--r--src/libsyntax/ext/pipes/pipec.rs19
-rw-r--r--src/libsyntax/ext/pipes/proto.rs3
-rw-r--r--src/libsyntax/fold.rs4
-rw-r--r--src/libsyntax/parse/mod.rs4
-rw-r--r--src/libsyntax/parse/obsolete.rs5
-rw-r--r--src/libsyntax/parse/parser.rs63
-rw-r--r--src/libsyntax/print/pprust.rs17
-rw-r--r--src/libsyntax/visit.rs10
37 files changed, 197 insertions, 121 deletions
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 826b64b9a64..94cad18ece2 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -954,7 +954,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
         encode_name(ecx, ebml_w, item.ident);
         encode_attributes(ebml_w, item.attrs);
         match ty.node {
-            ast::ty_path(path, _) if path.idents.len() == 1 => {
+            ast::ty_path(path, bounds, _) if path.idents.len() == 1 => {
+                assert!(bounds.is_empty());
                 encode_impl_type_basename(ecx, ebml_w,
                                           ast_util::path_to_ident(path));
             }
diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index cf2a92b291f..b53bdcc9bbe 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -311,8 +311,9 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
         let substs = parse_substs(st, conv);
         let store = parse_trait_store(st);
         let mt = parse_mutability(st);
+        let bounds = parse_bounds(st, conv);
         assert_eq!(next(st), ']');
-        return ty::mk_trait(st.tcx, def, substs, store, mt);
+        return ty::mk_trait(st.tcx, def, substs, store, mt, bounds.builtin_bounds);
       }
       'p' => {
         let did = parse_def(st, TypeParameter, conv);
diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs
index 5f854b1f24e..dd62a8e11cb 100644
--- a/src/librustc/metadata/tyencode.rs
+++ b/src/librustc/metadata/tyencode.rs
@@ -261,13 +261,16 @@ fn enc_sty(w: @io::Writer, cx: @ctxt, st: ty::sty) {
         enc_substs(w, cx, substs);
         w.write_char(']');
       }
-      ty::ty_trait(def, ref substs, store, mt) => {
+      ty::ty_trait(def, ref substs, store, mt, bounds) => {
         w.write_str(&"x[");
         w.write_str((cx.ds)(def));
         w.write_char('|');
         enc_substs(w, cx, substs);
         enc_trait_store(w, cx, store);
         enc_mutability(w, mt);
+        let bounds = ty::ParamBounds {builtin_bounds: bounds,
+                                      trait_bounds: ~[]};
+        enc_bounds(w, cx, &bounds);
         w.write_char(']');
       }
       ty::ty_tup(ts) => {
diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs
index 6492850b668..1768852bb30 100644
--- a/src/librustc/middle/kind.rs
+++ b/src/librustc/middle/kind.rs
@@ -129,7 +129,8 @@ fn check_item(item: @item, (cx, visitor): (Context, visit::vt<Context>)) {
                         if cx.tcx.lang_items.drop_trait() == trait_def_id {
                             // Yes, it's a destructor.
                             match self_type.node {
-                                ty_path(_, path_node_id) => {
+                                ty_path(_, bounds, path_node_id) => {
+                                    assert!(bounds.is_empty());
                                     let struct_def = cx.tcx.def_map.get_copy(
                                         &path_node_id);
                                     let struct_did =
@@ -307,7 +308,7 @@ pub fn check_expr(e: @expr, (cx, v): (Context, visit::vt<Context>)) {
 
 fn check_ty(aty: @Ty, (cx, v): (Context, visit::vt<Context>)) {
     match aty.node {
-      ty_path(_, id) => {
+      ty_path(_, _, id) => {
           let r = cx.tcx.node_type_substs.find(&id);
           for r.iter().advance |ts| {
               let did = ast_util::def_id_of_def(cx.tcx.def_map.get_copy(&id));
@@ -533,7 +534,8 @@ pub fn check_cast_for_escaping_regions(
 pub fn check_kind_bounds_of_cast(cx: Context, source: @expr, target: @expr) {
     let target_ty = ty::expr_ty(cx.tcx, target);
     match ty::get(target_ty).sty {
-        ty::ty_trait(_, _, ty::UniqTraitStore, _) => {
+        // FIXME(#3569) kind check bounds here
+        ty::ty_trait(_, _, ty::UniqTraitStore, _, _bounds) => {
             let source_ty = ty::expr_ty(cx.tcx, source);
             if !ty::type_is_owned(cx.tcx, source_ty) {
                 cx.tcx.sess.span_err(
diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs
index d29c027f3c2..821aed731c2 100644
--- a/src/librustc/middle/lint.rs
+++ b/src/librustc/middle/lint.rs
@@ -714,7 +714,7 @@ fn check_item_ctypes(cx: &Context, it: @ast::item) {
         let tys = vec::map(decl.inputs, |a| a.ty );
         for vec::each(vec::append_one(tys, decl.output)) |ty| {
             match ty.node {
-              ast::ty_path(_, id) => {
+              ast::ty_path(_, _, id) => {
                 match cx.tcx.def_map.get_copy(&id) {
                   ast::def_prim_ty(ast::ty_int(ast::ty_i)) => {
                     cx.span_lint(ctypes, ty.span,
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 4b6cedd114c..0e6d8617ba4 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -804,7 +804,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty,
     // then check whether it is region-parameterized and consider
     // that as a direct dependency.
     match ty.node {
-      ast::ty_path(path, id) => {
+      ast::ty_path(path, _bounds, id) => {
         match cx.def_map.find(&id) {
           Some(&ast::def_ty(did)) |
           Some(&ast::def_trait(did)) |
@@ -840,7 +840,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty,
         visit_mt(mt, (cx, visitor));
       }
 
-      ast::ty_path(path, _) => {
+      ast::ty_path(path, _bounds, _) => {
         // type parameters are---for now, anyway---always invariant
         do cx.with_ambient_variance(rv_invariant) {
             for path.types.iter().advance |tp| {
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index fbea5d4adf2..eed0b12b9e1 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -1250,7 +1250,7 @@ impl Resolver {
                 // If there are static methods, then create the module
                 // and add them.
                 match (trait_ref_opt, ty) {
-                    (None, @Ty { node: ty_path(path, _), _ }) if
+                    (None, @Ty { node: ty_path(path, _, _), _ }) if
                             has_static_methods && path.idents.len() == 1 => {
                         let name = path_to_ident(path);
 
@@ -4120,7 +4120,7 @@ impl Resolver {
             // Like path expressions, the interpretation of path types depends
             // on whether the path has multiple elements in it or not.
 
-            ty_path(path, path_id) => {
+            ty_path(path, bounds, path_id) => {
                 // This is a path in the type namespace. Walk through scopes
                 // scopes looking for it.
                 let mut result_def = None;
@@ -4179,6 +4179,10 @@ impl Resolver {
                                            self.idents_to_str(path.idents)));
                     }
                 }
+
+                for bounds.each |bound| {
+                    self.resolve_type_parameter_bound(bound, visitor);
+                }
             }
 
             ty_closure(c) => {
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 2eadad7d8d1..11eecf82bac 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -561,7 +561,7 @@ fn create_ty(cx: @mut CrateContext, t: ty::t, span: span) -> DIType {
             cx.sess.span_note(span, "debuginfo for closure NYI");
             create_unimpl_ty(cx, t)
         },
-        ty::ty_trait(_did, ref _substs, ref _vstore, _) => {
+        ty::ty_trait(_did, ref _substs, ref _vstore, _, _bounds) => {
             cx.sess.span_note(span, "debuginfo for trait NYI");
             create_unimpl_ty(cx, t)
         },
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 58f04ab3b2e..7d86f743a8e 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -683,7 +683,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
         }
         ast::expr_cast(val, _) => {
             match ty::get(node_id_type(bcx, expr.id)).sty {
-                ty::ty_trait(_, _, store, _) => {
+                ty::ty_trait(_, _, store, _, _) => {
                     return meth::trans_trait_cast(bcx, val, expr.id, dest,
                                                   store);
                 }
diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs
index e9febb51005..d8ba524b2bd 100644
--- a/src/librustc/middle/trans/glue.rs
+++ b/src/librustc/middle/trans/glue.rs
@@ -486,13 +486,13 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
       ty::ty_closure(_) => {
         closure::make_closure_glue(bcx, v0, t, drop_ty)
       }
-      ty::ty_trait(_, _, ty::BoxTraitStore, _) => {
+      ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
           let llbox_ptr = GEPi(bcx, v0, [0u, abi::trt_field_box]);
           let llbox = Load(bcx, llbox_ptr);
           decr_refcnt_maybe_free(bcx, llbox, Some(llbox_ptr),
                                  ty::mk_opaque_box(ccx.tcx))
       }
-      ty::ty_trait(_, _, ty::UniqTraitStore, _) => {
+      ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
           let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
           // Only drop the value when it is non-null
           do with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue))) |bcx| {
@@ -571,12 +571,12 @@ pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) {
       ty::ty_closure(_) => {
         closure::make_closure_glue(bcx, v, t, take_ty)
       }
-      ty::ty_trait(_, _, ty::BoxTraitStore, _) => {
+      ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
         let llbox = Load(bcx, GEPi(bcx, v, [0u, abi::trt_field_box]));
         incr_refcnt_of_boxed(bcx, llbox);
         bcx
       }
-      ty::ty_trait(_, _, ty::UniqTraitStore, _) => {
+      ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
           let lluniquevalue = GEPi(bcx, v, [0, abi::trt_field_box]);
           let llvtable = Load(bcx, GEPi(bcx, v, [0, abi::trt_field_vtable]));
 
diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs
index fd382a869df..4f4bbf84a72 100644
--- a/src/librustc/middle/trans/monomorphize.rs
+++ b/src/librustc/middle/trans/monomorphize.rs
@@ -293,7 +293,7 @@ pub fn normalize_for_monomorphization(tcx: ty::ctxt,
         ty::ty_closure(ref fty) => {
             Some(normalized_closure_ty(tcx, fty.sigil))
         }
-        ty::ty_trait(_, _, ref store, _) => {
+        ty::ty_trait(_, _, ref store, _, _) => {
             let sigil = match *store {
                 ty::UniqTraitStore => ast::OwnedSigil,
                 ty::BoxTraitStore => ast::ManagedSigil,
diff --git a/src/librustc/middle/trans/reachable.rs b/src/librustc/middle/trans/reachable.rs
index 5cb52d2a057..6a40c1f75e9 100644
--- a/src/librustc/middle/trans/reachable.rs
+++ b/src/librustc/middle/trans/reachable.rs
@@ -160,7 +160,7 @@ fn traverse_ty<'a>(ty: @Ty, (cx, v): (@mut ctx<'a>, visit::vt<@mut ctx<'a>>)) {
     }
 
     match ty.node {
-      ty_path(p, p_id) => {
+      ty_path(p, _bounds, p_id) => {
         match cx.tcx.def_map.find(&p_id) {
           // Kind of a hack to check this here, but I'm not sure what else
           // to do
diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs
index cb68a2af92b..316eb6893f2 100644
--- a/src/librustc/middle/trans/reflect.rs
+++ b/src/librustc/middle/trans/reflect.rs
@@ -335,7 +335,7 @@ impl Reflector {
           }
 
           // Miscallaneous extra types
-          ty::ty_trait(_, _, _, _) => self.leaf(~"trait"),
+          ty::ty_trait(_, _, _, _, _) => self.leaf(~"trait"),
           ty::ty_infer(_) => self.leaf(~"infer"),
           ty::ty_err => self.leaf(~"err"),
           ty::ty_param(ref p) => {
diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs
index 448ded6b70f..3699314a1d2 100644
--- a/src/librustc/middle/trans/type_of.rs
+++ b/src/librustc/middle/trans/type_of.rs
@@ -140,7 +140,7 @@ pub fn sizing_type_of(cx: &mut CrateContext, t: ty::t) -> Type {
 
         ty::ty_bare_fn(*) => Type::i8p(),
         ty::ty_closure(*) => Type::struct_([Type::i8p(), Type::i8p()], false),
-        ty::ty_trait(_, _, store, _) => Type::opaque_trait(cx, store),
+        ty::ty_trait(_, _, store, _, _) => Type::opaque_trait(cx, store),
 
         ty::ty_estr(ty::vstore_fixed(size)) => Type::array(&Type::i8(), size as u64),
         ty::ty_evec(mt, ty::vstore_fixed(size)) => {
@@ -271,7 +271,7 @@ pub fn type_of(cx: &mut CrateContext, t: ty::t) -> Type {
           let ty = type_of_fn_from_ty(cx, t);
           Type::func_pair(cx, &ty)
       }
-      ty::ty_trait(_, _, store, _) => Type::opaque_trait(cx, store),
+      ty::ty_trait(_, _, store, _, _) => Type::opaque_trait(cx, store),
       ty::ty_type => cx.tydesc_type.ptr_to(),
       ty::ty_tup(*) => {
           let repr = adt::represent_type(cx, t);
diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs
index 49cb3bd51dd..f2446d1a115 100644
--- a/src/librustc/middle/trans/type_use.rs
+++ b/src/librustc/middle/trans/type_use.rs
@@ -208,7 +208,7 @@ pub fn type_needs_inner(cx: Context,
                 ty::ty_bare_fn(*) |
                 ty::ty_ptr(_) |
                 ty::ty_rptr(_, _) |
-                ty::ty_trait(_, _, _, _) => false,
+                ty::ty_trait(*) => false,
 
               ty::ty_enum(did, ref substs) => {
                 if list::find(enums_seen, |id| *id == did).is_none() {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index a367cf4c430..b76f30a7041 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -419,7 +419,8 @@ impl to_bytes::IterBytes for ClosureTy {
         self.sigil.iter_bytes(lsb0, f) &&
         self.onceness.iter_bytes(lsb0, f) &&
         self.region.iter_bytes(lsb0, f) &&
-        self.sig.iter_bytes(lsb0, f)
+        self.sig.iter_bytes(lsb0, f) &&
+        self.bounds.iter_bytes(lsb0, f)
     }
 }
 
@@ -600,7 +601,7 @@ pub enum sty {
     ty_rptr(Region, mt),
     ty_bare_fn(BareFnTy),
     ty_closure(ClosureTy),
-    ty_trait(def_id, substs, TraitStore, ast::mutability),
+    ty_trait(def_id, substs, TraitStore, ast::mutability, BuiltinBounds),
     ty_struct(def_id, substs),
     ty_tup(~[t]),
 
@@ -1046,7 +1047,7 @@ fn mk_t(cx: ctxt, st: sty) -> t {
       &ty_infer(_) => flags |= needs_infer as uint,
       &ty_self(_) => flags |= has_self as uint,
       &ty_enum(_, ref substs) | &ty_struct(_, ref substs) |
-      &ty_trait(_, ref substs, _, _) => {
+      &ty_trait(_, ref substs, _, _, _) => {
         flags |= sflags(substs);
       }
       &ty_box(ref m) | &ty_uniq(ref m) | &ty_evec(ref m, _) |
@@ -1268,10 +1269,11 @@ pub fn mk_trait(cx: ctxt,
                 did: ast::def_id,
                 substs: substs,
                 store: TraitStore,
-                mutability: ast::mutability)
+                mutability: ast::mutability,
+                bounds: BuiltinBounds)
              -> t {
     // take a copy of substs so that we own the vectors inside
-    mk_t(cx, ty_trait(did, substs, store, mutability))
+    mk_t(cx, ty_trait(did, substs, store, mutability, bounds))
 }
 
 pub fn mk_struct(cx: ctxt, struct_id: ast::def_id, substs: substs) -> t {
@@ -1319,7 +1321,7 @@ pub fn maybe_walk_ty(ty: t, f: &fn(t) -> bool) {
         maybe_walk_ty(tm.ty, f);
       }
       ty_enum(_, ref substs) | ty_struct(_, ref substs) |
-      ty_trait(_, ref substs, _, _) => {
+      ty_trait(_, ref substs, _, _, _) => {
         for (*substs).tps.iter().advance |subty| { maybe_walk_ty(*subty, f); }
       }
       ty_tup(ref ts) => { for ts.iter().advance |tt| { maybe_walk_ty(*tt, f); } }
@@ -1380,8 +1382,8 @@ fn fold_sty(sty: &sty, fldop: &fn(t) -> t) -> sty {
         ty_enum(tid, ref substs) => {
             ty_enum(tid, fold_substs(substs, fldop))
         }
-        ty_trait(did, ref substs, st, mutbl) => {
-            ty_trait(did, fold_substs(substs, fldop), st, mutbl)
+        ty_trait(did, ref substs, st, mutbl, bounds) => {
+            ty_trait(did, fold_substs(substs, fldop), st, mutbl, bounds)
         }
         ty_tup(ref ts) => {
             let new_ts = ts.map(|tt| fldop(*tt));
@@ -1470,8 +1472,12 @@ pub fn fold_regions_and_ty(
       ty_struct(def_id, ref substs) => {
         ty::mk_struct(cx, def_id, fold_substs(substs, fldr, fldt))
       }
-      ty_trait(def_id, ref substs, st, mutbl) => {
-        ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), st, mutbl)
+      ty_trait(def_id, ref substs, st, mutbl, bounds) => {
+        let st = match st {
+            RegionTraitStore(region) => RegionTraitStore(fldr(region)),
+            st => st,
+        };
+        ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), st, mutbl, bounds)
       }
       ty_bare_fn(ref f) => {
           ty::mk_bare_fn(cx, BareFnTy {sig: fold_sig(&f.sig, fldfnt),
@@ -2054,18 +2060,18 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
                 TC_MANAGED + statically_sized(nonowned(tc_mt(cx, mt, cache)))
             }
 
-            ty_trait(_, _, UniqTraitStore, _) => {
+            ty_trait(_, _, UniqTraitStore, _, _bounds) => {
                 TC_OWNED_CLOSURE
             }
 
-            ty_trait(_, _, BoxTraitStore, mutbl) => {
+            ty_trait(_, _, BoxTraitStore, mutbl, _bounds) => {
                 match mutbl {
                     ast::m_mutbl => TC_MANAGED + TC_MUTABLE,
                     _ => TC_MANAGED
                 }
             }
 
-            ty_trait(_, _, RegionTraitStore(r), mutbl) => {
+            ty_trait(_, _, RegionTraitStore(r), mutbl, _bounds) => {
                 borrowed_contents(r, mutbl)
             }
 
@@ -2347,7 +2353,7 @@ pub fn is_instantiable(cx: ctxt, r_ty: t) -> bool {
                 false           // unsafe ptrs can always be NULL
             }
 
-            ty_trait(_, _, _, _) => {
+            ty_trait(_, _, _, _, _) => {
                 false
             }
 
@@ -2500,7 +2506,7 @@ pub fn type_is_pod(cx: ctxt, ty: t) -> bool {
       ty_box(_) | ty_uniq(_) | ty_closure(_) |
       ty_estr(vstore_uniq) | ty_estr(vstore_box) |
       ty_evec(_, vstore_uniq) | ty_evec(_, vstore_box) |
-      ty_trait(_, _, _, _) | ty_rptr(_,_) | ty_opaque_box => result = false,
+      ty_trait(_, _, _, _, _) | ty_rptr(_,_) | ty_opaque_box => result = false,
       // Structural types
       ty_enum(did, ref substs) => {
         let variants = enum_variants(cx, did);
@@ -2791,12 +2797,13 @@ impl to_bytes::IterBytes for sty {
 
             ty_uniq(ref mt) => 19u8.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f),
 
-            ty_trait(ref did, ref substs, ref v, ref mutbl) => {
+            ty_trait(ref did, ref substs, ref v, ref mutbl, bounds) => {
                 20u8.iter_bytes(lsb0, f) &&
                 did.iter_bytes(lsb0, f) &&
                 substs.iter_bytes(lsb0, f) &&
                 v.iter_bytes(lsb0, f) &&
-                mutbl.iter_bytes(lsb0, f)
+                mutbl.iter_bytes(lsb0, f) &&
+                bounds.iter_bytes(lsb0, f)
             }
 
             ty_opaque_closure_ptr(ref ck) => 21u8.iter_bytes(lsb0, f) && ck.iter_bytes(lsb0, f),
@@ -3440,7 +3447,7 @@ pub fn ty_sort_str(cx: ctxt, t: t) -> ~str {
       ty_rptr(_, _) => ~"&-ptr",
       ty_bare_fn(_) => ~"extern fn",
       ty_closure(_) => ~"fn",
-      ty_trait(id, _, _, _) => fmt!("trait %s", item_path_str(cx, id)),
+      ty_trait(id, _, _, _, _) => fmt!("trait %s", item_path_str(cx, id)),
       ty_struct(id, _) => fmt!("struct %s", item_path_str(cx, id)),
       ty_tup(_) => ~"tuple",
       ty_infer(TyVar(_)) => ~"inferred type",
@@ -3774,7 +3781,7 @@ pub fn impl_trait_ref(cx: ctxt, id: ast::def_id) -> Option<@TraitRef> {
 
 pub fn ty_to_def_id(ty: t) -> Option<ast::def_id> {
     match get(ty).sty {
-      ty_trait(id, _, _, _) | ty_struct(id, _) | ty_enum(id, _) => Some(id),
+      ty_trait(id, _, _, _, _) | ty_struct(id, _) | ty_enum(id, _) => Some(id),
       _ => None
     }
 }
@@ -4454,5 +4461,6 @@ pub fn visitor_object_ty(tcx: ctxt) -> (@TraitRef, t) {
     assert!(tcx.intrinsic_traits.contains_key(&ty_visitor_name));
     let trait_ref = tcx.intrinsic_traits.get_copy(&ty_visitor_name);
     (trait_ref,
-     mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs, BoxTraitStore, ast::m_imm))
+     mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs,
+              BoxTraitStore, ast::m_imm, EmptyBuiltinBounds()))
 }
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index 660ff83b5b3..3b651451db8 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -277,7 +277,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
                 }
                 return ty::mk_evec(tcx, mt, vst);
             }
-            ast::ty_path(path, id) => {
+            ast::ty_path(path, bounds, id) => {
+                // Note that the "bounds must be empty if path is not a trait"
+                // restriction is enforced in the below case for ty_path, which
+                // will run after this as long as the path isn't a trait.
                 match tcx.def_map.find(&id) {
                     Some(&ast::def_prim_ty(ast::ty_str)) if a_seq_ty.mutbl == ast::m_imm => {
                         check_path_args(tcx, path, NO_TPS | NO_REGIONS);
@@ -300,11 +303,13 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
                                 ty::BoxTraitStore
                             }
                         };
+                        let bounds = conv_builtin_bounds(this.tcx(), bounds);
                         return ty::mk_trait(tcx,
                                             result.def_id,
                                             copy result.substs,
                                             trait_store,
-                                            a_seq_ty.mutbl);
+                                            a_seq_ty.mutbl,
+                                            bounds);
                     }
                     _ => {}
                 }
@@ -395,13 +400,22 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
                                       ast_ty.span);
           ty::mk_closure(tcx, fn_decl)
       }
-      ast::ty_path(path, id) => {
+      ast::ty_path(path, bounds, id) => {
         let a_def = match tcx.def_map.find(&id) {
           None => tcx.sess.span_fatal(
               ast_ty.span, fmt!("unbound path %s",
                                 path_to_str(path, tcx.sess.intr()))),
           Some(&d) => d
         };
+        // Kind bounds on path types are only supported for traits.
+        match a_def {
+            // But don't emit the error if the user meant to do a trait anyway.
+            ast::def_trait(*) => { },
+            _ if !bounds.is_empty() =>
+                tcx.sess.span_err(ast_ty.span,
+                    "kind bounds can only be used on trait types"),
+            _ => { },
+        }
         match a_def {
           ast::def_trait(_) => {
               let path_str = path_to_str(path, tcx.sess.intr());
diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs
index 33d1377d000..60855e6cd96 100644
--- a/src/librustc/middle/typeck/check/method.rs
+++ b/src/librustc/middle/typeck/check/method.rs
@@ -292,7 +292,7 @@ impl<'self> LookupContext<'self> {
                 ty_param(p) => {
                     self.push_inherent_candidates_from_param(self_ty, p);
                 }
-                ty_trait(did, ref substs, store, _) => {
+                ty_trait(did, ref substs, store, _, _) => {
                     self.push_inherent_candidates_from_trait(
                         self_ty, did, substs, store);
                     self.push_inherent_impl_candidates_for_type(did);
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index ac89c48a29b..69d4d82d15f 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -360,7 +360,7 @@ fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) {
             // explaining how it goes about doing that.
             let target_ty = rcx.resolve_node_type(expr.id);
             match ty::get(target_ty).sty {
-                ty::ty_trait(_, _, ty::RegionTraitStore(trait_region), _) => {
+                ty::ty_trait(_, _, ty::RegionTraitStore(trait_region), _, _) => {
                     let source_ty = rcx.fcx.expr_ty(source);
                     constrain_regions_in_type(rcx, trait_region,
                                               expr.span, source_ty);
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index 5ce95e23e2c..bd78e9cc5fb 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -139,10 +139,11 @@ fn fixup_substs(vcx: &VtableContext, location_info: &LocationInfo,
     let t = ty::mk_trait(tcx,
                          id, substs,
                          ty::RegionTraitStore(ty::re_static),
-                         ast::m_imm);
+                         ast::m_imm,
+                         ty::EmptyBuiltinBounds());
     do fixup_ty(vcx, location_info, t, is_early).map |t_f| {
         match ty::get(*t_f).sty {
-          ty::ty_trait(_, ref substs_f, _, _) => (/*bad*/copy *substs_f),
+          ty::ty_trait(_, ref substs_f, _, _, _) => (/*bad*/copy *substs_f),
           _ => fail!("t_f should be a trait")
         }
     }
@@ -530,7 +531,9 @@ pub fn early_resolve_expr(ex: @ast::expr,
           debug!("vtable resolution on expr %s", ex.repr(fcx.tcx()));
           let target_ty = fcx.expr_ty(ex);
           match ty::get(target_ty).sty {
-              ty::ty_trait(target_def_id, ref target_substs, store, target_mutbl) => {
+              // Bounds of type's contents are not checked here, but in kind.rs.
+              ty::ty_trait(target_def_id, ref target_substs, store,
+                           target_mutbl, _bounds) => {
                   fn mutability_allowed(a_mutbl: ast::mutability,
                                         b_mutbl: ast::mutability) -> bool {
                       a_mutbl == b_mutbl ||
diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs
index bf935d92c75..7ad27077cd8 100644
--- a/src/librustc/middle/typeck/coherence.rs
+++ b/src/librustc/middle/typeck/coherence.rs
@@ -114,7 +114,7 @@ pub fn type_is_defined_in_local_crate(original_type: t) -> bool {
     do ty::walk_ty(original_type) |t| {
         match get(t).sty {
             ty_enum(def_id, _) |
-            ty_trait(def_id, _, _, _) |
+            ty_trait(def_id, _, _, _, _) |
             ty_struct(def_id, _) => {
                 if def_id.crate == ast::local_crate {
                     found_nominal = true;
@@ -140,7 +140,7 @@ pub fn get_base_type_def_id(inference_context: @mut InferCtxt,
             match get(base_type).sty {
                 ty_enum(def_id, _) |
                 ty_struct(def_id, _) |
-                ty_trait(def_id, _, _, _) => {
+                ty_trait(def_id, _, _, _, _) => {
                     return Some(def_id);
                 }
                 _ => {
@@ -753,7 +753,7 @@ impl CoherenceChecker {
     pub fn ast_type_is_defined_in_local_crate(&self, original_type: @ast::Ty)
                                               -> bool {
         match original_type.node {
-            ty_path(_, path_id) => {
+            ty_path(_, _, path_id) => {
                 match self.crate_context.tcx.def_map.get_copy(&path_id) {
                     def_ty(def_id) | def_struct(def_id) => {
                         if def_id.crate != local_crate {
diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs
index 773860ffc64..884f72b57f0 100644
--- a/src/librustc/middle/typeck/infer/combine.rs
+++ b/src/librustc/middle/typeck/infer/combine.rs
@@ -508,13 +508,15 @@ pub fn super_tys<C:Combine>(
           }
       }
 
-      (&ty::ty_trait(a_id, ref a_substs, a_store, a_mutbl),
-       &ty::ty_trait(b_id, ref b_substs, b_store, b_mutbl))
+      (&ty::ty_trait(a_id, ref a_substs, a_store, a_mutbl, a_bounds),
+       &ty::ty_trait(b_id, ref b_substs, b_store, b_mutbl, b_bounds))
       if a_id == b_id && a_mutbl == b_mutbl => {
           let trait_def = ty::lookup_trait_def(tcx, a_id);
           do this.substs(&trait_def.generics, a_substs, b_substs).chain |substs| {
               do this.trait_stores(ty::terr_trait, a_store, b_store).chain |s| {
-                  Ok(ty::mk_trait(tcx, a_id, /*bad*/copy substs, s, a_mutbl))
+                  do this.bounds(a_bounds, b_bounds).chain |bounds| {
+                    Ok(ty::mk_trait(tcx, a_id, /*bad*/copy substs, s, a_mutbl, bounds))
+                  }
               }
           }
       }
diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs
index 2e83acfa9f4..1bfe452f25e 100644
--- a/src/librustc/middle/typeck/infer/mod.rs
+++ b/src/librustc/middle/typeck/infer/mod.rs
@@ -717,10 +717,11 @@ impl InferCtxt {
                                   trait_ref.def_id,
                                   copy trait_ref.substs,
                                   ty::UniqTraitStore,
-                                  ast::m_imm);
+                                  ast::m_imm,
+                                  ty::EmptyBuiltinBounds());
         let dummy1 = self.resolve_type_vars_if_possible(dummy0);
         match ty::get(dummy1).sty {
-            ty::ty_trait(ref def_id, ref substs, _, _) => {
+            ty::ty_trait(ref def_id, ref substs, _, _, _) => {
                 ty::TraitRef {def_id: *def_id,
                               substs: copy *substs}
             }
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index c730e74c903..2a0b97d4cb1 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -365,6 +365,8 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
 
         s.push_str("fn");
 
+        s.push_str(cty.bounds.repr(cx));
+
         push_sig_to_str(cx, &mut s, &cty.sig);
 
         return s;
@@ -451,11 +453,13 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
         let base = ast_map::path_to_str(path, cx.sess.intr());
         parameterized(cx, base, substs.self_r, substs.tps)
       }
-      ty_trait(did, ref substs, s, mutbl) => {
+      ty_trait(did, ref substs, s, mutbl, ref bounds) => {
         let path = ty::item_path(cx, did);
         let base = ast_map::path_to_str(path, cx.sess.intr());
         let ty = parameterized(cx, base, substs.self_r, substs.tps);
-        fmt!("%s%s%s", trait_store_to_str(cx, s), mutability_to_str(mutbl), ty)
+        let bound_str = bounds.repr(cx);
+        fmt!("%s%s%s%s", trait_store_to_str(cx, s), mutability_to_str(mutbl), ty,
+                         bound_str)
       }
       ty_evec(ref mt, vs) => {
         vstore_ty_to_str(cx, mt, vs)
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 1758433aa73..2e3d557daa9 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -797,7 +797,7 @@ pub enum ty_ {
     ty_closure(@TyClosure),
     ty_bare_fn(@TyBareFn),
     ty_tup(~[@Ty]),
-    ty_path(@Path, node_id),
+    ty_path(@Path, @OptVec<TyParamBound>, node_id),
     ty_mac(mac),
     // ty_infer means the type should be inferred instead of it having been
     // specified. This should only appear at the "top level" of a type and not
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 34c247662a4..24cf5662a36 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -473,7 +473,7 @@ pub fn id_visitor<T: Copy>(vfn: @fn(node_id, T)) -> visit::vt<T> {
 
         visit_ty: |ty, (t, vt)| {
             match ty.node {
-              ty_path(_, id) => vfn(id, copy t),
+              ty_path(_, _, id) => vfn(id, copy t),
               _ => { /* fall through */ }
             }
             visit::visit_ty(ty, (t, vt));
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index dc31a248065..b6399794477 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -48,7 +48,7 @@ pub trait AstBuilder {
     fn ty_mt(&self, ty: @ast::Ty, mutbl: ast::mutability) -> ast::mt;
 
     fn ty(&self, span: span, ty: ast::ty_) -> @ast::Ty;
-    fn ty_path(&self, @ast::Path) -> @ast::Ty;
+    fn ty_path(&self, @ast::Path, @OptVec<ast::TyParamBound>) -> @ast::Ty;
     fn ty_ident(&self, span: span, idents: ast::ident) -> @ast::Ty;
 
     fn ty_rptr(&self, span: span,
@@ -267,14 +267,17 @@ impl AstBuilder for @ExtCtxt {
         }
     }
 
-    fn ty_path(&self, path: @ast::Path) -> @ast::Ty {
+    fn ty_path(&self, path: @ast::Path, bounds: @OptVec<ast::TyParamBound>)
+              -> @ast::Ty {
         self.ty(path.span,
-                ast::ty_path(path, self.next_id()))
+                ast::ty_path(path, bounds, self.next_id()))
     }
 
+    // Might need to take bounds as an argument in the future, if you ever want
+    // to generate a bounded existential trait type.
     fn ty_ident(&self, span: span, ident: ast::ident)
         -> @ast::Ty {
-        self.ty_path(self.path_ident(span, ident))
+        self.ty_path(self.path_ident(span, ident), @opt_vec::Empty)
     }
 
     fn ty_rptr(&self,
@@ -304,7 +307,8 @@ impl AstBuilder for @ExtCtxt {
                               self.ident_of("Option")
                           ],
                           None,
-                          ~[ ty ]))
+                          ~[ ty ]),
+            @opt_vec::Empty)
     }
 
     fn ty_field_imm(&self, span: span, name: ident, ty: @ast::Ty) -> ast::ty_field {
@@ -342,7 +346,7 @@ impl AstBuilder for @ExtCtxt {
     fn ty_vars_global(&self, ty_params: &OptVec<ast::TyParam>) -> ~[@ast::Ty] {
         opt_vec::take_vec(
             ty_params.map(|p| self.ty_path(
-                self.path_global(dummy_sp(), ~[p.ident]))))
+                self.path_global(dummy_sp(), ~[p.ident]), @opt_vec::Empty)))
     }
 
     fn strip_bounds(&self, generics: &Generics) -> Generics {
diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs
index dca1b7bbd59..981b28afd02 100644
--- a/src/libsyntax/ext/deriving/generic.rs
+++ b/src/libsyntax/ext/deriving/generic.rs
@@ -358,7 +358,8 @@ impl<'self> TraitDef<'self> {
 
         // Create the type of `self`.
         let self_type = cx.ty_path(cx.path_all(span, false, ~[ type_ident ], self_lifetime,
-                                               opt_vec::take_vec(self_ty_params)));
+                                               opt_vec::take_vec(self_ty_params)),
+                                   @opt_vec::Empty);
 
         let doc_attr = cx.attribute(
             span,
diff --git a/src/libsyntax/ext/deriving/ty.rs b/src/libsyntax/ext/deriving/ty.rs
index 3b39cb691a6..d28613f52fa 100644
--- a/src/libsyntax/ext/deriving/ty.rs
+++ b/src/libsyntax/ext/deriving/ty.rs
@@ -65,7 +65,7 @@ impl<'self> Path<'self> {
                  self_generics: &Generics)
                  -> @ast::Ty {
         cx.ty_path(self.to_path(cx, span,
-                                self_ty, self_generics))
+                                self_ty, self_generics), @opt_vec::Empty)
     }
     pub fn to_path(&self,
                    cx: @ExtCtxt,
@@ -144,7 +144,8 @@ impl<'self> Ty<'self> {
             }
             Literal(ref p) => { p.to_ty(cx, span, self_ty, self_generics) }
             Self  => {
-                cx.ty_path(self.to_path(cx, span, self_ty, self_generics))
+                cx.ty_path(self.to_path(cx, span, self_ty, self_generics),
+                           @opt_vec::Empty)
             }
             Tuple(ref fields) => {
                 let ty = if fields.is_empty() {
diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs
index 8478a827e85..a20528082ab 100644
--- a/src/libsyntax/ext/pipes/pipec.rs
+++ b/src/libsyntax/ext/pipes/pipec.rs
@@ -61,7 +61,7 @@ impl gen_send for message {
 
             let pipe_ty = cx.ty_path(
                 path(~[this.data_name()], span)
-                .add_tys(cx.ty_vars(&this.generics.ty_params)));
+                .add_tys(cx.ty_vars(&this.generics.ty_params)), @opt_vec::Empty);
             let args_ast = vec::append(
                 ~[cx.arg(span, cx.ident_of("pipe"), pipe_ty)],
                 args_ast);
@@ -117,7 +117,7 @@ impl gen_send for message {
 
             let mut rty = cx.ty_path(path(~[next.data_name()],
                                           span)
-                                     .add_tys(copy next_state.tys));
+                                     .add_tys(copy next_state.tys), @opt_vec::Empty);
             if try {
                 rty = cx.ty_option(rty);
             }
@@ -146,7 +146,7 @@ impl gen_send for message {
                              cx.ty_path(
                                  path(~[this.data_name()], span)
                                  .add_tys(cx.ty_vars(
-                                     &this.generics.ty_params))))],
+                                     &this.generics.ty_params)), @opt_vec::Empty))],
                     args_ast);
 
                 let message_args = if arg_names.len() == 0 {
@@ -192,7 +192,7 @@ impl gen_send for message {
 
     fn to_ty(&mut self, cx: @ExtCtxt) -> @ast::Ty {
         cx.ty_path(path(~[cx.ident_of(self.name())], self.span())
-          .add_tys(cx.ty_vars(&self.get_generics().ty_params)))
+          .add_tys(cx.ty_vars(&self.get_generics().ty_params)), @opt_vec::Empty)
     }
 }
 
@@ -226,7 +226,7 @@ impl to_type_decls for state {
                                 cx.ty_path(
                                     path(~[cx.ident_of(dir),
                                            cx.ident_of(next_name)], span)
-                                    .add_tys(copy next_state.tys)))
+                                    .add_tys(copy next_state.tys), @opt_vec::Empty))
               }
               None => tys
             };
@@ -279,7 +279,8 @@ impl to_type_decls for state {
                                    self.data_name()],
                                  dummy_sp())
                             .add_tys(cx.ty_vars(
-                                &self.generics.ty_params))))),
+                                &self.generics.ty_params)), @opt_vec::Empty)),
+                        @opt_vec::Empty),
                     cx.strip_bounds(&self.generics)));
         }
         else {
@@ -298,8 +299,8 @@ impl to_type_decls for state {
                                    self.data_name()],
                                         dummy_sp())
                             .add_tys(cx.ty_vars_global(
-                                &self.generics.ty_params))),
-                                   self.proto.buffer_ty_path(cx)])),
+                                &self.generics.ty_params)), @opt_vec::Empty),
+                                   self.proto.buffer_ty_path(cx)]), @opt_vec::Empty),
                     cx.strip_bounds(&self.generics)));
         };
         items
@@ -384,7 +385,7 @@ impl gen_init for protocol {
         cx.ty_path(path(~[cx.ident_of("super"),
                           cx.ident_of("__Buffer")],
                         copy self.span)
-                   .add_tys(cx.ty_vars_global(&params)))
+                   .add_tys(cx.ty_vars_global(&params)), @opt_vec::Empty)
     }
 
     fn gen_buffer_type(&self, cx: @ExtCtxt) -> @ast::item {
diff --git a/src/libsyntax/ext/pipes/proto.rs b/src/libsyntax/ext/pipes/proto.rs
index d00f1fd7746..87aaf7781fa 100644
--- a/src/libsyntax/ext/pipes/proto.rs
+++ b/src/libsyntax/ext/pipes/proto.rs
@@ -15,6 +15,7 @@ use codemap::span;
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
 use ext::pipes::ast_builder::{append_types, path};
+use opt_vec;
 
 #[deriving(Eq)]
 pub enum direction { send, recv }
@@ -101,7 +102,7 @@ impl state_ {
     pub fn to_ty(&self, cx: @ExtCtxt) -> @ast::Ty {
         cx.ty_path
             (path(~[cx.ident_of(self.name)],self.span).add_tys(
-                cx.ty_vars(&self.generics.ty_params)))
+                cx.ty_vars(&self.generics.ty_params)), @opt_vec::Empty)
     }
 
     /// Iterate over the states that can be reached in one message
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 568324bc599..4bd2c0a3de1 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -680,7 +680,9 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
             })
         }
         ty_tup(ref tys) => ty_tup(tys.map(|ty| fld.fold_ty(*ty))),
-        ty_path(path, id) => ty_path(fld.fold_path(path), fld.new_id(id)),
+        ty_path(path, bounds, id) =>
+            ty_path(fld.fold_path(path),
+                    @bounds.map(|x| fold_ty_param_bound(x, fld)), fld.new_id(id)),
         ty_fixed_length_vec(ref mt, e) => {
             ty_fixed_length_vec(
                 fold_mt(mt, fld),
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 5edd2ec4d47..0c5731c8b29 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -494,7 +494,7 @@ mod test {
                                         idents:~[str_to_ident("int")],
                                         rp: None,
                                         types: ~[]},
-                                                       2),
+                                                       @opt_vec::Empty, 2),
                                     span:sp(4,7)},
                        pat: @ast::pat{id:1,
                                       node: ast::pat_ident(ast::bind_infer,
@@ -530,7 +530,7 @@ mod test {
                                         idents:~[str_to_ident("int")],
                                         rp: None,
                                         types: ~[]},
-                                                       2),
+                                                       @opt_vec::Empty, 2),
                                                 span:sp(10,13)},
                                     pat: @ast::pat{id:1, // fixme
                                                    node: ast::pat_ident(
diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs
index bb315bf2933..19b4d254580 100644
--- a/src/libsyntax/parse/obsolete.rs
+++ b/src/libsyntax/parse/obsolete.rs
@@ -46,7 +46,6 @@ pub enum ObsoleteSyntax {
     ObsoleteUnsafeBlock,
     ObsoleteUnenforcedBound,
     ObsoleteImplSyntax,
-    ObsoleteTraitBoundSeparator,
     ObsoleteMutOwnedPointer,
     ObsoleteMutVector,
     ObsoleteImplVisibility,
@@ -143,10 +142,6 @@ impl Parser {
                 "colon-separated impl syntax",
                 "write `impl Trait for Type`"
             ),
-            ObsoleteTraitBoundSeparator => (
-                "space-separated trait bounds",
-                "write `+` between trait bounds"
-            ),
             ObsoleteMutOwnedPointer => (
                 "const or mutable owned pointer",
                 "mutability inherits through `~` pointers; place the `~` box
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 753c69b23d6..f2443f9e533 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -75,7 +75,7 @@ use parse::obsolete::{ObsoleteLet, ObsoleteFieldTerminator};
 use parse::obsolete::{ObsoleteMoveInit, ObsoleteBinaryMove, ObsoleteSwap};
 use parse::obsolete::{ObsoleteSyntax, ObsoleteLowerCaseKindBounds};
 use parse::obsolete::{ObsoleteUnsafeBlock, ObsoleteImplSyntax};
-use parse::obsolete::{ObsoleteTraitBoundSeparator, ObsoleteMutOwnedPointer};
+use parse::obsolete::{ObsoleteMutOwnedPointer};
 use parse::obsolete::{ObsoleteMutVector, ObsoleteImplVisibility};
 use parse::obsolete::{ObsoleteRecordType, ObsoleteRecordPattern};
 use parse::obsolete::{ObsoletePostFnTySigil};
@@ -710,8 +710,8 @@ impl Parser {
         } else if *self.token == token::MOD_SEP
             || is_ident_or_path(self.token) {
             // NAMED TYPE
-            let path = self.parse_path_with_tps(false);
-            ty_path(path, self.get_id())
+            let (path, bounds) = self.parse_type_path();
+            ty_path(path, @bounds, self.get_id())
         } else {
             self.fatal(fmt!("expected type, found token %?",
                             *self.token));
@@ -974,10 +974,8 @@ impl Parser {
                      types: ~[] }
     }
 
-    // parse a path optionally with type parameters. If 'colons'
-    // is true, then type parameters must be preceded by colons,
-    // as in a::t::<t1,t2>
-    pub fn parse_path_with_tps(&self, colons: bool) -> @ast::Path {
+    pub fn parse_bounded_path_with_tps(&self, colons: bool,
+                                        before_tps: Option<&fn()>) -> @ast::Path {
         debug!("parse_path_with_tps(colons=%b)", colons);
 
         maybe_whole!(self, nt_path);
@@ -987,6 +985,10 @@ impl Parser {
             return path;
         }
 
+        // If the path might have bounds on it, they should be parsed before
+        // the parameters, e.g. module::TraitName:B1+B2<T>
+        before_tps.map_consume(|callback| callback());
+
         // Parse the (obsolete) trailing region parameter, if any, which will
         // be written "foo/&x"
         let rp_slash = {
@@ -1038,6 +1040,25 @@ impl Parser {
                      .. copy *path }
     }
 
+    // parse a path optionally with type parameters. If 'colons'
+    // is true, then type parameters must be preceded by colons,
+    // as in a::t::<t1,t2>
+    pub fn parse_path_with_tps(&self, colons: bool) -> @ast::Path {
+        self.parse_bounded_path_with_tps(colons, None)
+    }
+
+    // Like the above, but can also parse kind bounds in the case of a
+    // path to be used as a type that might be a trait.
+    pub fn parse_type_path(&self) -> (@ast::Path, OptVec<TyParamBound>) {
+        let mut bounds = opt_vec::Empty;
+        let path = self.parse_bounded_path_with_tps(false, Some(|| {
+            // Note: this closure might not even get called in the case of a
+            // macro-generated path. But that's the macro parser's job.
+            bounds = self.parse_optional_ty_param_bounds();
+        }));
+        (path, bounds)
+    }
+
     /// parses 0 or 1 lifetime
     pub fn parse_opt_lifetime(&self) -> Option<@ast::Lifetime> {
         match *self.token {
@@ -2847,16 +2868,6 @@ impl Parser {
         spanned(lo, hi, bloc)
     }
 
-    fn mk_ty_path(&self, i: ident) -> @Ty {
-        @Ty {
-            id: self.get_id(),
-            node: ty_path(
-                ident_to_path(*self.last_span, i),
-                self.get_id()),
-            span: *self.last_span,
-        }
-    }
-
     fn parse_optional_purity(&self) -> ast::purity {
         if self.eat_keyword(keywords::Pure) {
             self.obsolete(*self.last_span, ObsoletePurity);
@@ -2921,13 +2932,8 @@ impl Parser {
                 _ => break,
             }
 
-            if self.eat(&token::BINOP(token::PLUS)) {
-                loop;
-            }
-
-            if is_ident_or_path(self.token) {
-                self.obsolete(*self.span,
-                              ObsoleteTraitBoundSeparator);
+            if !self.eat(&token::BINOP(token::PLUS)) {
+                break;
             }
         }
 
@@ -3284,14 +3290,19 @@ impl Parser {
         let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) {
             // New-style trait. Reinterpret the type as a trait.
             let opt_trait_ref = match ty.node {
-                ty_path(path, node_id) => {
+                ty_path(path, @opt_vec::Empty, node_id) => {
                     Some(@trait_ref {
                         path: path,
                         ref_id: node_id
                     })
                 }
+                ty_path(*) => {
+                    self.span_err(ty.span,
+                                  "bounded traits are only valid in type position");
+                    None
+                }
                 _ => {
-                    self.span_err(*self.span, "not a trait");
+                    self.span_err(ty.span, "not a trait");
                     None
                 }
             };
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 8e47df51010..fa22b7ceb71 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -422,7 +422,7 @@ pub fn print_type(s: @ps, ty: @ast::Ty) {
                       f.purity, f.onceness, &f.decl, None,
                       Some(&generics), None);
       }
-      ast::ty_path(path, _) => print_path(s, path, false),
+      ast::ty_path(path, bounds, _) => print_bounded_path(s, path, bounds),
       ast::ty_fixed_length_vec(ref mt, v) => {
         word(s.s, "[");
         match mt.mutbl {
@@ -1483,7 +1483,8 @@ pub fn print_for_decl(s: @ps, loc: @ast::local, coll: @ast::expr) {
     print_expr(s, coll);
 }
 
-pub fn print_path(s: @ps, path: @ast::Path, colons_before_params: bool) {
+fn print_path_(s: @ps, path: @ast::Path, colons_before_params: bool,
+               opt_bounds: Option<@OptVec<ast::TyParamBound>>) {
     maybe_print_comment(s, path.span.lo);
     if path.global { word(s.s, "::"); }
     let mut first = true;
@@ -1491,6 +1492,9 @@ pub fn print_path(s: @ps, path: @ast::Path, colons_before_params: bool) {
         if first { first = false; } else { word(s.s, "::"); }
         print_ident(s, *id);
     }
+    do opt_bounds.map_consume |bounds| {
+        print_bounds(s, bounds);
+    };
     if path.rp.is_some() || !path.types.is_empty() {
         if colons_before_params { word(s.s, "::"); }
 
@@ -1511,6 +1515,15 @@ pub fn print_path(s: @ps, path: @ast::Path, colons_before_params: bool) {
     }
 }
 
+pub fn print_path(s: @ps, path: @ast::Path, colons_before_params: bool) {
+    print_path_(s, path, colons_before_params, None)
+}
+
+pub fn print_bounded_path(s: @ps, path: @ast::Path,
+                          bounds: @OptVec<ast::TyParamBound>) {
+    print_path_(s, path, false, Some(bounds))
+}
+
 pub fn print_irrefutable_pat(s: @ps, pat: @ast::pat) {
     print_pat(s, pat, false)
 }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index e7afeb12a61..5aa38c0348c 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -247,13 +247,17 @@ pub fn visit_ty<E: Copy>(t: @Ty, (e, v): (E, vt<E>)) {
         },
         ty_closure(ref f) => {
             for f.decl.inputs.iter().advance |a| { (v.visit_ty)(a.ty, (copy e, v)); }
-            (v.visit_ty)(f.decl.output, (e, v));
+            (v.visit_ty)(f.decl.output, (copy e, v));
+            visit_ty_param_bounds(&f.bounds, (e, v));
         },
         ty_bare_fn(ref f) => {
             for f.decl.inputs.iter().advance |a| { (v.visit_ty)(a.ty, (copy e, v)); }
             (v.visit_ty)(f.decl.output, (e, v));
         },
-        ty_path(p, _) => visit_path(p, (e, v)),
+        ty_path(p, bounds, _) => {
+            visit_path(p, (copy e, v));
+            visit_ty_param_bounds(bounds, (e, v));
+        },
         ty_fixed_length_vec(ref mt, ex) => {
             (v.visit_ty)(mt.ty, (copy e, v));
             (v.visit_expr)(ex, (copy e, v));
@@ -328,7 +332,7 @@ pub fn visit_foreign_item<E: Copy>(ni: @foreign_item, (e, v): (E, vt<E>)) {
     }
 }
 
-pub fn visit_ty_param_bounds<E: Copy>(bounds: @OptVec<TyParamBound>,
+pub fn visit_ty_param_bounds<E: Copy>(bounds: &OptVec<TyParamBound>,
                                       (e, v): (E, vt<E>)) {
     for bounds.each |bound| {
         match *bound {