about summary refs log tree commit diff
path: root/src/libsyntax/parse/parser.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-04-22 14:17:36 +0000
committerbors <bors@rust-lang.org>2017-04-22 14:17:36 +0000
commit9cc77d7690fc723b264962a4d01a6221be87d80e (patch)
tree35ab2d0889884041c889373f21e2347ef1de18a3 /src/libsyntax/parse/parser.rs
parent6d841da4a0d7629f826117f99052e3d4a7997a7e (diff)
parentb37163c81c44fa51f630adebec33aa90e2f2e432 (diff)
downloadrust-9cc77d7690fc723b264962a4d01a6221be87d80e.tar.gz
rust-9cc77d7690fc723b264962a4d01a6221be87d80e.zip
Auto merge of #41464 - frewsxcv:rollup, r=frewsxcv
Rollup of 3 pull requests

- Successful merges: #41077, #41355, #41450
- Failed merges:
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
-rw-r--r--src/libsyntax/parse/parser.rs101
1 files changed, 64 insertions, 37 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 0cdb09a842f..1baf0d1b54c 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -152,6 +152,7 @@ fn maybe_append(mut lhs: Vec<Attribute>, rhs: Option<Vec<Attribute>>)
 enum PrevTokenKind {
     DocComment,
     Comma,
+    Plus,
     Interpolated,
     Eof,
     Other,
@@ -1061,6 +1062,7 @@ impl<'a> Parser<'a> {
         self.prev_token_kind = match self.token {
             token::DocComment(..) => PrevTokenKind::DocComment,
             token::Comma => PrevTokenKind::Comma,
+            token::BinOp(token::Plus) => PrevTokenKind::Plus,
             token::Interpolated(..) => PrevTokenKind::Interpolated,
             token::Eof => PrevTokenKind::Eof,
             _ => PrevTokenKind::Other,
@@ -1354,20 +1356,26 @@ impl<'a> Parser<'a> {
                     break;
                 }
             }
+            let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus;
             self.expect(&token::CloseDelim(token::Paren))?;
 
             if ts.len() == 1 && !last_comma {
                 let ty = ts.into_iter().nth(0).unwrap().unwrap();
+                let maybe_bounds = allow_plus && self.token == token::BinOp(token::Plus);
                 match ty.node {
-                    // Accept `(Trait1) + Trait2 + 'a` for backward compatibility (#39318).
-                    TyKind::Path(None, ref path)
-                            if allow_plus && self.token == token::BinOp(token::Plus) => {
-                        self.bump(); // `+`
-                        let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo.to(self.prev_span));
-                        let mut bounds = vec![TraitTyParamBound(pt, TraitBoundModifier::None)];
-                        bounds.append(&mut self.parse_ty_param_bounds()?);
-                        TyKind::TraitObject(bounds)
+                    // `(TY_BOUND_NOPAREN) + BOUND + ...`.
+                    TyKind::Path(None, ref path) if maybe_bounds => {
+                        self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)?
                     }
+                    TyKind::TraitObject(ref bounds)
+                            if maybe_bounds && bounds.len() == 1 && !trailing_plus => {
+                        let path = match bounds[0] {
+                            TraitTyParamBound(ref pt, ..) => pt.trait_ref.path.clone(),
+                            _ => self.bug("unexpected lifetime bound"),
+                        };
+                        self.parse_remaining_bounds(Vec::new(), path, lo, true)?
+                    }
+                    // `(TYPE)`
                     _ => TyKind::Paren(P(ty))
                 }
             } else {
@@ -1418,11 +1426,8 @@ impl<'a> Parser<'a> {
                 // Just a type path or bound list (trait object type) starting with a trait.
                 //   `Type`
                 //   `Trait1 + Trait2 + 'a`
-                if allow_plus && self.eat(&token::BinOp(token::Plus)) {
-                    let poly_trait = PolyTraitRef::new(Vec::new(), path, lo.to(self.prev_span));
-                    let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)];
-                    bounds.append(&mut self.parse_ty_param_bounds()?);
-                    TyKind::TraitObject(bounds)
+                if allow_plus && self.check(&token::BinOp(token::Plus)) {
+                    self.parse_remaining_bounds(Vec::new(), path, lo, true)?
                 } else {
                     TyKind::Path(None, path)
                 }
@@ -1440,12 +1445,8 @@ impl<'a> Parser<'a> {
                 self.parse_ty_bare_fn(lifetime_defs)?
             } else {
                 let path = self.parse_path(PathStyle::Type)?;
-                let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
-                let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)];
-                if allow_plus && self.eat(&token::BinOp(token::Plus)) {
-                    bounds.append(&mut self.parse_ty_param_bounds()?)
-                }
-                TyKind::TraitObject(bounds)
+                let parse_plus = allow_plus && self.check(&token::BinOp(token::Plus));
+                self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)?
             }
         } else if self.eat_keyword(keywords::Impl) {
             // FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511).
@@ -1468,6 +1469,17 @@ impl<'a> Parser<'a> {
         Ok(P(ty))
     }
 
+    fn parse_remaining_bounds(&mut self, lifetime_defs: Vec<LifetimeDef>, path: ast::Path,
+                              lo: Span, parse_plus: bool) -> PResult<'a, TyKind> {
+        let poly_trait_ref = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
+        let mut bounds = vec![TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)];
+        if parse_plus {
+            self.bump(); // `+`
+            bounds.append(&mut self.parse_ty_param_bounds()?);
+        }
+        Ok(TyKind::TraitObject(bounds))
+    }
+
     fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> {
         // Do not add `+` to expected tokens.
         if !allow_plus || self.token != token::BinOp(token::Plus) {
@@ -4070,28 +4082,43 @@ impl<'a> Parser<'a> {
     // Parse bounds of a type parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
     // BOUND = TY_BOUND | LT_BOUND
     // LT_BOUND = LIFETIME (e.g. `'a`)
-    // TY_BOUND = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`)
+    // TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
+    // TY_BOUND_NOPAREN = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`)
     fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> {
         let mut bounds = Vec::new();
         loop {
-            let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None };
-            if self.check_lifetime() {
-                if let Some(question_span) = question {
-                    self.span_err(question_span,
-                                  "`?` may only modify trait bounds, not lifetime bounds");
-                }
-                bounds.push(RegionTyParamBound(self.expect_lifetime()));
-            } else if self.check_keyword(keywords::For) || self.check_path() {
-                let lo = self.span;
-                let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
-                let path = self.parse_path(PathStyle::Type)?;
-                let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
-                let modifier = if question.is_some() {
-                    TraitBoundModifier::Maybe
+            let is_bound_start = self.check_path() || self.check_lifetime() ||
+                                 self.check(&token::Question) ||
+                                 self.check_keyword(keywords::For) ||
+                                 self.check(&token::OpenDelim(token::Paren));
+            if is_bound_start {
+                let has_parens = self.eat(&token::OpenDelim(token::Paren));
+                let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None };
+                if self.token.is_lifetime() {
+                    if let Some(question_span) = question {
+                        self.span_err(question_span,
+                                      "`?` may only modify trait bounds, not lifetime bounds");
+                    }
+                    bounds.push(RegionTyParamBound(self.expect_lifetime()));
                 } else {
-                    TraitBoundModifier::None
-                };
-                bounds.push(TraitTyParamBound(poly_trait, modifier));
+                    let lo = self.span;
+                    let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
+                    let path = self.parse_path(PathStyle::Type)?;
+                    let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
+                    let modifier = if question.is_some() {
+                        TraitBoundModifier::Maybe
+                    } else {
+                        TraitBoundModifier::None
+                    };
+                    bounds.push(TraitTyParamBound(poly_trait, modifier));
+                }
+                if has_parens {
+                    self.expect(&token::CloseDelim(token::Paren))?;
+                    if let Some(&RegionTyParamBound(..)) = bounds.last() {
+                        self.span_err(self.prev_span,
+                                      "parenthesized lifetime bounds are not supported");
+                    }
+                }
             } else {
                 break
             }