about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorBen Blum <bblum@andrew.cmu.edu>2013-06-17 15:16:30 -0400
committerBen Blum <bblum@andrew.cmu.edu>2013-06-23 14:40:14 -0400
commitce857e3d60da1b5eff5d830dbd03f32a8890ad16 (patch)
tree0874080aaf00735050a07a541f3f72b31818117d /src/libsyntax
parent394f455b5edfe96b51bc713ccc65ad3db6bed92f (diff)
downloadrust-ce857e3d60da1b5eff5d830dbd03f32a8890ad16.tar.gz
rust-ce857e3d60da1b5eff5d830dbd03f32a8890ad16.zip
Parse and typecheck (not kindcheck) bounds on trait paths.
Diffstat (limited to 'src/libsyntax')
-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
13 files changed, 93 insertions, 60 deletions
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 {