From 682033c4e47cf0cca5b4b96b07123da8807254f6 Mon Sep 17 00:00:00 2001 From: Crazycolorz5 Date: Fri, 25 May 2018 16:40:16 -0400 Subject: [PATCH 1/6] Implemented eat_plus and used it in parsing parse_ty_param_bounds_common. --- src/libsyntax/parse/parser.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 28f93328e9534..a4e2b96c5f99e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -880,6 +880,27 @@ impl<'a> Parser<'a> { false } } + + /// Expect and consume a `+`. if `+=` is seen, replace it with a `=` + /// and continue. If a `+` is not seen, return false. + /// + /// This is using when token splitting += into +. + /// See issue 47856 for an example of when this may occur. + fn eat_plus(&mut self) -> bool { + self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus))); + match self.token { + token::BinOp(token::Plus) => { + self.bump(); + true + } + token::BinOpEq(token::Plus) => { + let span = self.span.with_lo(self.span.lo() + BytePos(1)); + self.bump_with(token::Eq, span); + true + } + _ => false, + } + } /// Expect and consume an `&`. If `&&` is seen, replace it with a single /// `&` and continue. If an `&` is not seen, signal an error. @@ -4801,7 +4822,7 @@ impl<'a> Parser<'a> { break } - if !allow_plus || !self.eat(&token::BinOp(token::Plus)) { + if !allow_plus || !self.eat_plus() { break } } From 7a9ffa730740c18d23918add84c40bdf77f17dc0 Mon Sep 17 00:00:00 2001 From: Crazycolorz5 Date: Fri, 25 May 2018 17:09:32 -0400 Subject: [PATCH 2/6] Added is_like_plus to token, and used that in place of equality comparison to Plus token. --- src/libsyntax/parse/parser.rs | 31 ++++++++++++++++++++++--------- src/libsyntax/parse/token.rs | 7 +++++++ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a4e2b96c5f99e..a398962f66a58 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -901,6 +901,19 @@ impl<'a> Parser<'a> { _ => false, } } + + + /// Checks to see if the next token is either `+` or `+=`. + /// Otherwise returns false. + fn check_plus(&mut self) -> bool { + if self.token.is_like_plus() { + true + } + else { + self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus))); + false + } + } /// Expect and consume an `&`. If `&&` is seen, replace it with a single /// `&` and continue. If an `&` is not seen, signal an error. @@ -1533,7 +1546,7 @@ impl<'a> Parser<'a> { if ts.len() == 1 && !last_comma { let ty = ts.into_iter().nth(0).unwrap().into_inner(); - let maybe_bounds = allow_plus && self.token == token::BinOp(token::Plus); + let maybe_bounds = allow_plus && self.check_plus(); match ty.node { // `(TY_BOUND_NOPAREN) + BOUND + ...`. TyKind::Path(None, ref path) if maybe_bounds => { @@ -1602,7 +1615,7 @@ impl<'a> Parser<'a> { self.parse_ty_bare_fn(lifetime_defs)? } else { let path = self.parse_path(PathStyle::Type)?; - let parse_plus = allow_plus && self.check(&token::BinOp(token::Plus)); + let parse_plus = allow_plus && self.check_plus(); self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? } } else if self.eat_keyword(keywords::Impl) { @@ -1619,7 +1632,7 @@ impl<'a> Parser<'a> { impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn) } else if self.check(&token::Question) || - self.check_lifetime() && self.look_ahead(1, |t| t == &token::BinOp(token::Plus)) { + self.check_lifetime() && self.look_ahead(1, |t| t.is_like_plus()) { // Bound list (trait object type) TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?, TraitObjectSyntax::None) @@ -1639,7 +1652,7 @@ 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.check(&token::BinOp(token::Plus)) { + if allow_plus && self.check_plus() { self.parse_remaining_bounds(Vec::new(), path, lo, true)? } else { TyKind::Path(None, path) @@ -1666,7 +1679,7 @@ impl<'a> Parser<'a> { let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span)); let mut bounds = vec![TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)]; if parse_plus { - self.bump(); // `+` + self.eat_plus(); // `+` or `+=` gets split and `+` is discarded bounds.append(&mut self.parse_ty_param_bounds()?); } Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) @@ -1687,7 +1700,7 @@ impl<'a> Parser<'a> { 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) { + if !allow_plus || !self.token.is_like_plus() { return Ok(()) } @@ -4841,7 +4854,7 @@ impl<'a> Parser<'a> { while self.check_lifetime() { lifetimes.push(self.expect_lifetime()); - if !self.eat(&token::BinOp(token::Plus)) { + if !self.eat_plus() { break } } @@ -4987,7 +5000,7 @@ impl<'a> Parser<'a> { let mut seen_type = false; let mut seen_binding = false; loop { - if self.check_lifetime() && self.look_ahead(1, |t| t != &token::BinOp(token::Plus)) { + if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { // Parse lifetime argument. lifetimes.push(self.expect_lifetime()); if seen_type || seen_binding { @@ -5056,7 +5069,7 @@ impl<'a> Parser<'a> { loop { let lo = self.span; - if self.check_lifetime() && self.look_ahead(1, |t| t != &token::BinOp(token::Plus)) { + if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { let lifetime = self.expect_lifetime(); // Bounds starting with a colon are mandatory, but possibly empty. self.expect(&token::Colon)?; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 9770fbca8f86c..18665b99e2171 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -224,6 +224,13 @@ impl Token { _ => false, } } + + pub fn is_like_plus(&self) -> bool { + match *self { + BinOp(Plus) | BinOpEq(Plus) => true, + _ => false, + } + } /// Returns `true` if the token can appear at the start of an expression. pub fn can_begin_expr(&self) -> bool { From a5dc83d9708d83c9bdbbeb6fd7f12ceab2d92633 Mon Sep 17 00:00:00 2001 From: Crazycolorz5 Date: Fri, 25 May 2018 17:36:23 -0400 Subject: [PATCH 3/6] Tidy fixes. --- src/libsyntax/parse/parser.rs | 10 +++++----- src/libsyntax/parse/token.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a398962f66a58..a5129998e0fb9 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -880,11 +880,11 @@ impl<'a> Parser<'a> { false } } - + /// Expect and consume a `+`. if `+=` is seen, replace it with a `=` /// and continue. If a `+` is not seen, return false. /// - /// This is using when token splitting += into +. + /// This is using when token splitting += into +. /// See issue 47856 for an example of when this may occur. fn eat_plus(&mut self) -> bool { self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus))); @@ -901,8 +901,8 @@ impl<'a> Parser<'a> { _ => false, } } - - + + /// Checks to see if the next token is either `+` or `+=`. /// Otherwise returns false. fn check_plus(&mut self) -> bool { @@ -1679,7 +1679,7 @@ impl<'a> Parser<'a> { let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span)); let mut bounds = vec![TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)]; if parse_plus { - self.eat_plus(); // `+` or `+=` gets split and `+` is discarded + self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded bounds.append(&mut self.parse_ty_param_bounds()?); } Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 18665b99e2171..b4300feced4fa 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -224,7 +224,7 @@ impl Token { _ => false, } } - + pub fn is_like_plus(&self) -> bool { match *self { BinOp(Plus) | BinOpEq(Plus) => true, From 812ace6e86f9e4789136f721c4459e1e5f0a646c Mon Sep 17 00:00:00 2001 From: Crazycolorz5 Date: Fri, 25 May 2018 18:27:37 -0400 Subject: [PATCH 4/6] Fixed incorrect check_plus to token.is_like_plus. --- src/libsyntax/parse/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a5129998e0fb9..b49db70c42d21 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1546,7 +1546,7 @@ impl<'a> Parser<'a> { if ts.len() == 1 && !last_comma { let ty = ts.into_iter().nth(0).unwrap().into_inner(); - let maybe_bounds = allow_plus && self.check_plus(); + let maybe_bounds = allow_plus && self.token.is_like_plus(); match ty.node { // `(TY_BOUND_NOPAREN) + BOUND + ...`. TyKind::Path(None, ref path) if maybe_bounds => { From 2d00e5488e7528de5f058fb6487e40d37e18b2db Mon Sep 17 00:00:00 2001 From: "U-COLORZ-STRIX\\Crazycolorz5" Date: Tue, 29 May 2018 18:19:14 -0400 Subject: [PATCH 5/6] Added test case to make sure parsing of += is done correctly. --- .../parse-fail/trait-plusequal-splitting.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/parse-fail/trait-plusequal-splitting.rs diff --git a/src/test/parse-fail/trait-plusequal-splitting.rs b/src/test/parse-fail/trait-plusequal-splitting.rs new file mode 100644 index 0000000000000..cbb955fe61d03 --- /dev/null +++ b/src/test/parse-fail/trait-plusequal-splitting.rs @@ -0,0 +1,20 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only +// Fixes issue where `+` in generics weren't parsed if they were part of a `+=`. + +struct Whitespace { t: T } +struct TokenSplit { t: T } + +fn main() { +} + +FAIL //~ ERROR From 759a0e07b58e8b231091854b4e7e2f0ee8a8eddc Mon Sep 17 00:00:00 2001 From: Crazycolorz5 Date: Fri, 1 Jun 2018 09:52:51 -0400 Subject: [PATCH 6/6] Fixed indentation error. --- src/libsyntax/parse/parser.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b49db70c42d21..f3b656b71bb72 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -910,8 +910,8 @@ impl<'a> Parser<'a> { true } else { - self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus))); - false + self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus))); + false } }