From 9784d3543f524f142aae52da9d2a6ce1eb9d702a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 21 Sep 2018 04:26:36 +0300 Subject: [PATCH] parser: Tweak function parameter parsing to avoid rollback on succesfull path --- src/libsyntax/parse/parser.rs | 60 +++++++++++++++-------------------- 1 file changed, 25 insertions(+), 35 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6ec1ad969ee..963a7206bd6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1780,27 +1780,32 @@ fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> { (pat, self.parse_ty()?) } else { debug!("parse_arg_general ident_to_pat"); - - let parser_snapshot_before_pat = self.clone(); - - // Once we can use edition 2018 in the compiler, - // replace this with real try blocks. - macro_rules! try_block { - ($($inside:tt)*) => ( - (||{ ::std::ops::Try::from_ok({ $($inside)* }) })() - ) + let parser_snapshot_before_ty = self.clone(); + let mut ty = self.parse_ty(); + if ty.is_ok() && self.token == token::Colon { + // This wasn't actually a type, but a pattern looking like a type, + // so we are going to rollback and re-parse for recovery. + ty = self.unexpected(); } + match ty { + Ok(ty) => { + let ident = Ident::new(keywords::Invalid.name(), self.prev_span); + let pat = P(Pat { + id: ast::DUMMY_NODE_ID, + node: PatKind::Ident( + BindingMode::ByValue(Mutability::Immutable), ident, None), + span: ty.span, + }); + (pat, ty) + } + Err(mut err) => { + // Recover from attempting to parse the argument as a type without pattern. + err.cancel(); + mem::replace(self, parser_snapshot_before_ty); + let pat = self.parse_pat()?; + self.expect(&token::Colon)?; + let ty = self.parse_ty()?; - // We're going to try parsing the argument as a pattern (even though it's not - // allowed). This way we can provide better errors to the user. - let pat_arg: PResult<'a, _> = try_block! { - let pat = self.parse_pat()?; - self.expect(&token::Colon)?; - (pat, self.parse_ty()?) - }; - - match pat_arg { - Ok((pat, ty)) => { let mut err = self.diagnostic().struct_span_err_with_code( pat.span, "patterns aren't allowed in methods without bodies", @@ -1813,6 +1818,7 @@ macro_rules! try_block { Applicability::MachineApplicable, ); err.emit(); + // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. let pat = P(Pat { node: PatKind::Wild, @@ -1821,22 +1827,6 @@ macro_rules! try_block { }); (pat, ty) } - Err(mut err) => { - err.cancel(); - // Recover from attempting to parse the argument as a pattern. This means - // the type is alone, with no name, e.g. `fn foo(u32)`. - mem::replace(self, parser_snapshot_before_pat); - debug!("parse_arg_general ident_to_pat"); - let ident = Ident::new(keywords::Invalid.name(), self.prev_span); - let ty = self.parse_ty()?; - let pat = P(Pat { - id: ast::DUMMY_NODE_ID, - node: PatKind::Ident( - BindingMode::ByValue(Mutability::Immutable), ident, None), - span: ty.span, - }); - (pat, ty) - } } };