about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2014-08-27 21:46:52 -0400
committerNiko Matsakis <niko@alum.mit.edu>2014-08-27 21:46:52 -0400
commit1b487a890695e7d6dfbfe5dcd7d4fa0e8ca8003f (patch)
tree552fabade603ab0d148a49ae3cf1abd3f399740a /src/libsyntax/parse
parent3ee047ae1ffab454270bc1859b3beef3556ef8f9 (diff)
downloadrust-1b487a890695e7d6dfbfe5dcd7d4fa0e8ca8003f.tar.gz
rust-1b487a890695e7d6dfbfe5dcd7d4fa0e8ca8003f.zip
Implement generalized object and type parameter bounds (Fixes #16462)
Diffstat (limited to 'src/libsyntax/parse')
-rw-r--r--src/libsyntax/parse/parser.rs184
1 files changed, 71 insertions, 113 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 816700681cf..37bda15ac2c 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -12,7 +12,7 @@
 
 use abi;
 use ast::{BareFnTy, ClosureTy};
-use ast::{StaticRegionTyParamBound, OtherRegionTyParamBound, TraitTyParamBound};
+use ast::{RegionTyParamBound, TraitTyParamBound};
 use ast::{ProvidedMethod, Public, FnStyle};
 use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue};
 use ast::{BiBitAnd, BiBitOr, BiBitXor, Block};
@@ -70,7 +70,7 @@ use parse;
 use parse::attr::ParserAttr;
 use parse::classify;
 use parse::common::{SeqSep, seq_sep_none};
-use parse::common::{seq_sep_trailing_disallowed, seq_sep_trailing_allowed};
+use parse::common::{seq_sep_trailing_allowed};
 use parse::lexer::Reader;
 use parse::lexer::TokenAndSpan;
 use parse::obsolete::*;
@@ -120,7 +120,7 @@ pub enum PathParsingMode {
 /// A path paired with optional type bounds.
 pub struct PathAndBounds {
     pub path: ast::Path,
-    pub bounds: Option<OwnedSlice<TyParamBound>>,
+    pub bounds: Option<ast::TyParamBounds>,
 }
 
 enum ItemOrViewItem {
@@ -309,7 +309,7 @@ pub struct Parser<'a> {
     pub tokens_consumed: uint,
     pub restriction: restriction,
     pub quote_depth: uint, // not (yet) related to the quasiquoter
-    pub reader: Box<Reader>,
+    pub reader: Box<Reader+'a>,
     pub interner: Rc<token::IdentInterner>,
     /// The set of seen errors about obsolete syntax. Used to suppress
     /// extra detail when the same error is seen twice
@@ -346,8 +346,11 @@ fn real_token(rdr: &mut Reader) -> TokenAndSpan {
 }
 
 impl<'a> Parser<'a> {
-    pub fn new(sess: &'a ParseSess, cfg: ast::CrateConfig,
-               mut rdr: Box<Reader>) -> Parser<'a> {
+    pub fn new(sess: &'a ParseSess,
+               cfg: ast::CrateConfig,
+               mut rdr: Box<Reader+'a>)
+               -> Parser<'a>
+    {
         let tok0 = real_token(rdr);
         let span = tok0.sp;
         let placeholder = TokenAndSpan {
@@ -1073,14 +1076,7 @@ impl<'a> Parser<'a> {
         };
 
         let (inputs, variadic) = self.parse_fn_args(false, false);
-        let bounds = {
-            if self.eat(&token::COLON) {
-                let (_, bounds) = self.parse_ty_param_bounds(false);
-                Some(bounds)
-            } else {
-                None
-            }
-        };
+        let bounds = self.parse_colon_then_ty_param_bounds();
         let (ret_style, ret_ty) = self.parse_ret_ty();
         let decl = P(FnDecl {
             inputs: inputs,
@@ -1168,14 +1164,7 @@ impl<'a> Parser<'a> {
             (optional_unboxed_closure_kind, inputs)
         };
 
-        let (region, bounds) = {
-            if self.eat(&token::COLON) {
-                let (region, bounds) = self.parse_ty_param_bounds(true);
-                (region, Some(bounds))
-            } else {
-                (None, None)
-            }
-        };
+        let bounds = self.parse_colon_then_ty_param_bounds();
 
         let (return_style, output) = self.parse_ret_ty();
         let decl = P(FnDecl {
@@ -1199,7 +1188,7 @@ impl<'a> Parser<'a> {
                     bounds: bounds,
                     decl: decl,
                     lifetimes: lifetime_defs,
-                }, region)
+                })
             }
         }
     }
@@ -1687,7 +1676,7 @@ impl<'a> Parser<'a> {
             Some(INTERPOLATED(token::NtPath(box path))) => {
                 return PathAndBounds {
                     path: path,
-                    bounds: None,
+                    bounds: None
                 }
             }
             _ => {}
@@ -1744,25 +1733,31 @@ impl<'a> Parser<'a> {
             }
         }
 
-        // Next, parse a plus and bounded type parameters, if applicable.
-        let bounds = if mode == LifetimeAndTypesAndBounds {
-            let bounds = {
-                if self.eat(&token::BINOP(token::PLUS)) {
-                    let (_, bounds) = self.parse_ty_param_bounds(false);
-                    if bounds.len() == 0 {
-                        let last_span = self.last_span;
-                        self.span_err(last_span,
-                                      "at least one type parameter bound \
-                                       must be specified after the `+`");
-                    }
-                    Some(bounds)
-                } else {
-                    None
+        // Next, parse a plus and bounded type parameters, if
+        // applicable. We need to remember whether the separate was
+        // present for later, because in some contexts it's a parse
+        // error.
+        let opt_bounds = {
+            if mode == LifetimeAndTypesAndBounds &&
+                self.eat(&token::BINOP(token::PLUS))
+            {
+                let bounds = self.parse_ty_param_bounds();
+
+                // For some reason that I do not fully understand, we
+                // do not permit an empty list in the case where it is
+                // introduced by a `+`, but we do for `:` and other
+                // separators. -nmatsakis
+                if bounds.len() == 0 {
+                    let last_span = self.last_span;
+                    self.span_err(last_span,
+                                  "at least one type parameter bound \
+                                   must be specified");
                 }
-            };
-            bounds
-        } else {
-            None
+
+                Some(bounds)
+            } else {
+                None
+            }
         };
 
         // Assemble the span.
@@ -1775,7 +1770,7 @@ impl<'a> Parser<'a> {
                 global: is_global,
                 segments: segments,
             },
-            bounds: bounds,
+            bounds: opt_bounds,
         }
     }
 
@@ -3604,45 +3599,34 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// matches optbounds = ( ( : ( boundseq )? )? )
-    /// where   boundseq  = ( bound + boundseq ) | bound
-    /// and     bound     = 'static | ty
-    /// Returns "None" if there's no colon (e.g. "T");
-    /// Returns "Some(Empty)" if there's a colon but nothing after (e.g. "T:")
-    /// Returns "Some(stuff)" otherwise (e.g. "T:stuff").
-    /// NB: The None/Some distinction is important for issue #7264.
-    ///
-    /// Note that the `allow_any_lifetime` argument is a hack for now while the
-    /// AST doesn't support arbitrary lifetimes in bounds on type parameters. In
-    /// the future, this flag should be removed, and the return value of this
-    /// function should be Option<~[TyParamBound]>
-    fn parse_ty_param_bounds(&mut self, allow_any_lifetime: bool)
-                             -> (Option<ast::Lifetime>,
-                                 OwnedSlice<TyParamBound>) {
-        let mut ret_lifetime = None;
+    // Parses a sequence of bounds if a `:` is found,
+    // otherwise returns empty list.
+    fn parse_colon_then_ty_param_bounds(&mut self)
+                                        -> OwnedSlice<TyParamBound>
+    {
+        if !self.eat(&token::COLON) {
+            OwnedSlice::empty()
+        } else {
+            self.parse_ty_param_bounds()
+        }
+    }
+
+    // matches bounds    = ( boundseq )?
+    // where   boundseq  = ( bound + boundseq ) | bound
+    // and     bound     = 'region | ty
+    // NB: The None/Some distinction is important for issue #7264.
+    fn parse_ty_param_bounds(&mut self)
+                             -> OwnedSlice<TyParamBound>
+    {
         let mut result = vec!();
         loop {
             match self.token {
                 token::LIFETIME(lifetime) => {
-                    let lifetime_interned_string = token::get_ident(lifetime);
-                    if lifetime_interned_string.equiv(&("'static")) {
-                        result.push(StaticRegionTyParamBound);
-                        if allow_any_lifetime && ret_lifetime.is_none() {
-                            ret_lifetime = Some(ast::Lifetime {
-                                id: ast::DUMMY_NODE_ID,
-                                span: self.span,
-                                name: lifetime.name
-                            });
-                        }
-                    } else if allow_any_lifetime && ret_lifetime.is_none() {
-                        ret_lifetime = Some(ast::Lifetime {
-                            id: ast::DUMMY_NODE_ID,
-                            span: self.span,
-                            name: lifetime.name
-                        });
-                    } else {
-                        result.push(OtherRegionTyParamBound(self.span));
-                    }
+                    result.push(RegionTyParamBound(ast::Lifetime {
+                        id: ast::DUMMY_NODE_ID,
+                        span: self.span,
+                        name: lifetime.name
+                    }));
                     self.bump();
                 }
                 token::MOD_SEP | token::IDENT(..) => {
@@ -3662,7 +3646,7 @@ impl<'a> Parser<'a> {
             }
         }
 
-        return (ret_lifetime, OwnedSlice::from_vec(result));
+        return OwnedSlice::from_vec(result);
     }
 
     fn trait_ref_from_ident(ident: Ident, span: Span) -> ast::TraitRef {
@@ -3699,16 +3683,7 @@ impl<'a> Parser<'a> {
             ident = self.parse_ident();
         }
 
-        let opt_bounds = {
-            if self.eat(&token::COLON) {
-                let (_, bounds) = self.parse_ty_param_bounds(false);
-                Some(bounds)
-            } else {
-                None
-            }
-        };
-        // For typarams we don't care about the difference b/w "<T>" and "<T:>".
-        let bounds = opt_bounds.unwrap_or_default();
+        let bounds = self.parse_colon_then_ty_param_bounds();
 
         let default = if self.token == token::EQ {
             self.bump();
@@ -3797,7 +3772,7 @@ impl<'a> Parser<'a> {
             };
             self.expect(&token::COLON);
 
-            let (_, bounds) = self.parse_ty_param_bounds(false);
+            let bounds = self.parse_ty_param_bounds();
             let hi = self.span.hi;
             let span = mk_sp(lo, hi);
 
@@ -4273,19 +4248,13 @@ impl<'a> Parser<'a> {
         let mut tps = self.parse_generics();
         let sized = self.parse_for_sized();
 
-        // Parse traits, if necessary.
-        let traits;
-        if self.token == token::COLON {
-            self.bump();
-            traits = self.parse_trait_ref_list(&token::LBRACE);
-        } else {
-            traits = Vec::new();
-        }
+        // Parse supertrait bounds.
+        let bounds = self.parse_colon_then_ty_param_bounds();
 
         self.parse_where_clause(&mut tps);
 
         let meths = self.parse_trait_methods();
-        (ident, ItemTrait(tps, sized, traits, meths), None)
+        (ident, ItemTrait(tps, sized, bounds, meths), None)
     }
 
     fn parse_impl_items(&mut self) -> (Vec<ImplItem>, Vec<Attribute>) {
@@ -4319,12 +4288,10 @@ impl<'a> Parser<'a> {
             // New-style trait. Reinterpret the type as a trait.
             let opt_trait_ref = match ty.node {
                 TyPath(ref path, None, node_id) => {
-                    Some(TraitRef {
-                        path: /* bad */ (*path).clone(),
-                        ref_id: node_id
-                    })
+                    Some(TraitRef { path: (*path).clone(),
+                                    ref_id: node_id })
                 }
-                TyPath(..) => {
+                TyPath(_, Some(_), _) => {
                     self.span_err(ty.span,
                                   "bounded traits are only valid in type position");
                     None
@@ -4359,15 +4326,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Parse B + C<String,int> + D
-    fn parse_trait_ref_list(&mut self, ket: &token::Token) -> Vec<TraitRef> {
-        self.parse_seq_to_before_end(
-            ket,
-            seq_sep_trailing_disallowed(token::BINOP(token::PLUS)),
-            |p| p.parse_trait_ref()
-        )
-    }
-
     /// Parse struct Foo { ... }
     fn parse_item_struct(&mut self, is_virtual: bool) -> ItemInfo {
         let class_name = self.parse_ident();