]> git.lizzy.rs Git - rust.git/commitdiff
Parse and typecheck (not kindcheck) bounds on trait paths.
authorBen Blum <bblum@andrew.cmu.edu>
Mon, 17 Jun 2013 19:16:30 +0000 (15:16 -0400)
committerBen Blum <bblum@andrew.cmu.edu>
Sun, 23 Jun 2013 18:40:14 +0000 (14:40 -0400)
37 files changed:
src/librustc/metadata/encoder.rs
src/librustc/metadata/tydecode.rs
src/librustc/metadata/tyencode.rs
src/librustc/middle/kind.rs
src/librustc/middle/lint.rs
src/librustc/middle/region.rs
src/librustc/middle/resolve.rs
src/librustc/middle/trans/debuginfo.rs
src/librustc/middle/trans/expr.rs
src/librustc/middle/trans/glue.rs
src/librustc/middle/trans/monomorphize.rs
src/librustc/middle/trans/reachable.rs
src/librustc/middle/trans/reflect.rs
src/librustc/middle/trans/type_of.rs
src/librustc/middle/trans/type_use.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/astconv.rs
src/librustc/middle/typeck/check/method.rs
src/librustc/middle/typeck/check/regionck.rs
src/librustc/middle/typeck/check/vtable.rs
src/librustc/middle/typeck/coherence.rs
src/librustc/middle/typeck/infer/combine.rs
src/librustc/middle/typeck/infer/mod.rs
src/librustc/util/ppaux.rs
src/libsyntax/ast.rs
src/libsyntax/ast_util.rs
src/libsyntax/ext/build.rs
src/libsyntax/ext/deriving/generic.rs
src/libsyntax/ext/deriving/ty.rs
src/libsyntax/ext/pipes/pipec.rs
src/libsyntax/ext/pipes/proto.rs
src/libsyntax/fold.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/obsolete.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs

index 826b64b9a64b8e28ac5267ea40bf98947d9a5db6..94cad18ece2cdcf8f702bf8be515e1c0e0ffe4b1 100644 (file)
@@ -954,7 +954,8 @@ fn add_to_index_(item: @item, ebml_w: &writer::Encoder,
         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));
             }
index cf2a92b291f2883641dfc92e92f3a063f0a5715e..b53bdcc9bbe0bf2870e880c6fe6aeb3585a34b79 100644 (file)
@@ -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);
index 5f854b1f24e0d8c69172148ea5e15af7d15c264f..dd62a8e11cb7f797bfdc052bcad007cbdc0dda89 100644 (file)
@@ -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) => {
index 6492850b6685f23887b4b5753c1b6ec7a57167d5..1768852bb3031e8e6db186a3ea079cd670170142 100644 (file)
@@ -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 @@ fn is_subregion_of(cx: Context, r_sub: ty::Region, r_sup: ty::Region) -> bool {
 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(
index d29c027f3c28104bd13f0f628992b713f7aa901c..821aed731c2298d108cd36308e26d721b90b5713 100644 (file)
@@ -714,7 +714,7 @@ fn check_foreign_fn(cx: &Context, decl: &ast::fn_decl) {
         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,
index 4b6cedd114c31f16170535ae67c105127963d734..0e6d8617ba424003c580b886d4326a77cb719055 100644 (file)
@@ -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| {
index fbea5d4adf2ac25a60089398a80c66d41020452b..eed0b12b9e123a0f89807336c05e60e94babb1d6 100644 (file)
@@ -1250,7 +1250,7 @@ pub fn build_reduced_graph_for_item(@mut self,
                 // 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 @@ pub fn resolve_type(@mut self, ty: @Ty, visitor: ResolveVisitor) {
             // 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 @@ pub fn resolve_type(@mut self, ty: @Ty, visitor: ResolveVisitor) {
                                            self.idents_to_str(path.idents)));
                     }
                 }
+
+                for bounds.each |bound| {
+                    self.resolve_type_parameter_bound(bound, visitor);
+                }
             }
 
             ty_closure(c) => {
index 2eadad7d8d1bae9dead432a0cef270d8329c871d..11eecf82bacaf7416ed26b1916cb55e8b5573feb 100644 (file)
@@ -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)
         },
index 58f04ab3b2ec422f81664f27b62e096db566fa17..7d86f743a8e48a92529692c9b5756dc774c416a2 100644 (file)
@@ -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);
                 }
index e9febb51005cf92533c6198695d72e68583f7cfd..d8ba524b2bd117657629874255251df39c57b0ea 100644 (file)
@@ -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]));
 
index fd382a869dfa67922b618ff7242db93c1472efbf..4f4bbf84a72bff5cf9eff4e11fbc8330f12a484d 100644 (file)
@@ -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,
index 5cb52d2a057979d6034ae705d48d40f580e11d29..6a40c1f75e9eee41f6ea2e0d9faeb4888a268e93 100644 (file)
@@ -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
index cb68a2af92bb78c3744cc219df4cc2438ca108b7..316eb6893f25b8111fefbbae7977f7d606b096f8 100644 (file)
@@ -335,7 +335,7 @@ pub fn visit_ty(&mut self, t: ty::t) {
           }
 
           // 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) => {
index 448ded6b70f2ab1215243f921ffc47a4554bff63..3699314a1d2cf561d051c826af90b003f0b81f47 100644 (file)
@@ -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);
index 49cb3bd51ddb3f2a5c42814206c49d5ba89dddd9..f2446d1a11536e71359152be9b57e725505a069b 100644 (file)
@@ -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() {
index a367cf4c430a7b6e1ac7c04ea7f7bb64e8ec6ecd..b76f30a704108ab511e94b137c2be2ec555de60e 100644 (file)
@@ -419,7 +419,8 @@ fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
         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 sflags(substs: &substs) -> uint {
       &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_substs(substs: &substs, fldop: &fn(t) -> t) -> substs {
         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 @@ fn fold_substs(
       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 @@ fn tc_ty(cx: ctxt,
                 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 @@ fn subtypes_require(cx: ctxt, seen: &mut ~[def_id],
                 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 @@ fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
 
             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()))
 }
index 660ff83b5b3e6391412b3d21d7283dc36fdc2f07..3b651451db84777061eb7dd700711caf9d678d28 100644 (file)
@@ -277,7 +277,10 @@ fn mk_pointer<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 @@ fn mk_pointer<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 @@ fn check_path_args(tcx: ty::ctxt,
                                       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());
index 33d1377d000d0c7ff19735c9ae2a31a441aae9ee..60855e6cd96987b7415fc11854a6c6155d6c83e2 100644 (file)
@@ -292,7 +292,7 @@ pub fn push_inherent_candidates(&self, self_ty: ty::t) {
                 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);
index ac89c48a29b2c679fc80a1164cd2b32990ff939e..69d4d82d15f28e5b49ae9e29c152f79ec5b6b6ba 100644 (file)
@@ -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);
index 5ce95e23e2c7a4907166b610aed5dba068b04f52..bd78e9cc5fb46cbb98dc187580dc3a172f0f53e8 100644 (file)
@@ -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 ||
index bf935d92c75c3b90b1f5fe9818f1d1761b67dd92..7ad27077cd8673f2e8ecd632360561a772a14358 100644 (file)
@@ -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 @@ pub fn please_check_that_trait_methods_are_implemented(&self,
     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 {
index 773860ffc64bf369b8c9f433db92827521acc3b7..884f72b57f081cc4b08491719df634bf939d87b9 100644 (file)
@@ -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))
+                  }
               }
           }
       }
index 2e83acfa9f4b16f92173de18aecb3fb930e44374..1bfe452f25e09a54448abb6a6ed8ed228a2d66a1 100644 (file)
@@ -717,10 +717,11 @@ pub fn resolve_type_vars_in_trait_ref_if_possible(@mut self,
                                   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}
             }
index c730e74c903671f189fb6b6f5899b4ef91d049c3..2a0b97d4cb1b34c479e238cb6327301aeb074f15 100644 (file)
@@ -365,6 +365,8 @@ fn closure_to_str(cx: ctxt, cty: &ty::ClosureTy) -> ~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 @@ fn field_to_str(cx: ctxt, f: field) -> ~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)
index 1758433aa7375c8927ae16fb6de23a27a5bf3f76..2e3d557daa90f21a00e8be83040281e072840723 100644 (file)
@@ -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
index 34c247662a4e175a85fb8b8ff98e852aedc81f5a..24cf5662a36b1c372bbce9c58a4b2df4d6c36349 100644 (file)
@@ -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));
index dc31a248065da247759b29207fe4d3b8dc19a75b..b63997944774526ca97c11fcfeb2637f248394cd 100644 (file)
@@ -48,7 +48,7 @@ fn path_all(&self, sp: span,
     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 @@ fn ty(&self, span: span, ty: ast::ty_) -> @ast::Ty {
         }
     }
 
-    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 @@ fn ty_option(&self, ty: @ast::Ty) -> @ast::Ty {
                               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 @@ fn ty_vars(&self, ty_params: &OptVec<ast::TyParam>) -> ~[@ast::Ty] {
     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 {
index dca1b7bbd593458fd6e6f96203d90e1b8bf7769d..981b28afd022755ad61794203674635563cad274 100644 (file)
@@ -358,7 +358,8 @@ fn create_derived_impl(&self, cx: @ExtCtxt, span: span,
 
         // 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,
index 3b39cb691a629927a792a551e49f10ba5f6c4998..d28613f52faf795f6280e419df3b8a63e53c0e3b 100644 (file)
@@ -65,7 +65,7 @@ pub fn to_ty(&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 @@ pub fn to_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() {
index 8478a827e85d529df6684cca8497c55af236a6c2..a20528082ab55dd59769cc1d8fc456534784838c 100644 (file)
@@ -61,7 +61,7 @@ fn gen_send(&mut self, cx: @ExtCtxt, try: bool) -> @ast::item {
 
             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 @@ fn gen_send(&mut self, cx: @ExtCtxt, try: bool) -> @ast::item {
 
             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 @@ fn gen_send(&mut self, cx: @ExtCtxt, try: bool) -> @ast::item {
                              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 @@ fn gen_send(&mut self, cx: @ExtCtxt, try: bool) -> @ast::item {
 
     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 @@ fn to_type_decls(&self, cx: @ExtCtxt) -> ~[@ast::item] {
                                 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 @@ fn to_endpoint_decls(&self, cx: @ExtCtxt,
                                    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 @@ fn to_endpoint_decls(&self, cx: @ExtCtxt,
                                    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 @@ fn buffer_ty_path(&self, cx: @ExtCtxt) -> @ast::Ty {
         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 {
index d00f1fd7746dea028113e3cefb34eb12858f0c2d..87aaf7781fae554de9ee5d6f066d0b25eff3b83f 100644 (file)
@@ -15,6 +15,7 @@
 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 @@ pub fn data_name(&self) -> ast::ident {
     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
index 568324bc599613f1e211ebafa0e2e129718d3ff5..4bd2c0a3de1ffcd02ff815adb115f96e5ed33d79 100644 (file)
@@ -680,7 +680,9 @@ fn fold_field(f: ty_field, fld: @ast_fold) -> ty_field {
             })
         }
         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),
index 5edd2ec4d47901c243b1c7108dc188dc1a06b0ce..0c5731c8b29b981ad7ca8b408e41bf18b307ce3a 100644 (file)
@@ -494,7 +494,7 @@ fn parser_done(p: Parser){
                                         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 @@ fn parser_done(p: Parser){
                                         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(
index bb315bf2933957dffa8a71eb263565cb03004c8e..19b4d254580811b6d7a733ec22d534ffd18aa66a 100644 (file)
@@ -46,7 +46,6 @@ pub enum ObsoleteSyntax {
     ObsoleteUnsafeBlock,
     ObsoleteUnenforcedBound,
     ObsoleteImplSyntax,
-    ObsoleteTraitBoundSeparator,
     ObsoleteMutOwnedPointer,
     ObsoleteMutVector,
     ObsoleteImplVisibility,
@@ -143,10 +142,6 @@ pub fn obsolete(&self, sp: span, kind: ObsoleteSyntax) {
                 "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
index 753c69b23d6a1420911ce031c6bc94635f46c4aa..f2443f9e533592dde6cb07f71036d61e4a289a73 100644 (file)
@@ -75,7 +75,7 @@
 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 @@ pub fn parse_ty(&self, _: bool) -> @Ty {
         } 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 @@ pub fn parse_path_without_tps(&self) -> @ast::Path {
                      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 @@ pub fn parse_path_with_tps(&self, colons: bool) -> @ast::Path {
             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 @@ pub fn parse_path_with_tps(&self, colons: bool) -> @ast::Path {
                      .. 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 @@ fn parse_block_tail_(&self, lo: BytePos, s: blk_check_mode,
         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 @@ fn parse_optional_ty_param_bounds(&self) -> OptVec<TyParamBound> {
                 _ => 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 @@ fn parse_item_impl(&self, visibility: ast::visibility) -> item_info {
         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
                 }
             };
index 8e47df510108812ed06381f99ef4b7ce9f00412b..fa22b7ceb71006026c526734669f550583c2271d 100644 (file)
@@ -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)
 }
index e7afeb12a618851db438d08e400b2e0165170e3b..5aa38c0348c003e0782ad92c0998629d08150d85 100644 (file)
@@ -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 {