From e4c3b49fe790dd23f32acace8157d897d31c0cb3 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 9 Aug 2018 23:23:08 +0100 Subject: [PATCH] Emit an error during parsing --- src/librustc_passes/ast_validation.rs | 21 ++---- src/libsyntax/parse/parser.rs | 104 +++++++++++++++----------- src/test/ui/E0642.stderr | 9 +-- 3 files changed, 74 insertions(+), 60 deletions(-) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 2195331f465ba..e15dab404f478 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -336,24 +336,19 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if let TraitItemKind::Method(ref sig, ref block) = trait_item.node { self.check_trait_fn_not_async(trait_item.span, sig.header.asyncness); self.check_trait_fn_not_const(sig.header.constness); - self.check_decl_no_pat(&sig.decl, |span, mut_ident| { - if mut_ident { - if block.is_none() { + if block.is_none() { + self.check_decl_no_pat(&sig.decl, |span, mut_ident| { + if mut_ident { self.session.buffer_lint( lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY, trait_item.id, span, "patterns aren't allowed in trait methods"); + } else { + struct_span_err!(self.session, span, E0642, + "patterns aren't allowed in trait methods").emit(); } - } else { - let mut err = struct_span_err!(self.session, span, E0642, - "patterns aren't allowed in trait methods"); - let suggestion = "give this argument a name or use an \ - underscore to ignore it instead of using a \ - tuple pattern"; - err.span_suggestion(span, suggestion, "_".to_owned()); - err.emit(); - } - }); + }); + } } } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a1dbe93fdfe35..9a49d705c464b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1744,54 +1744,74 @@ impl<'a> Parser<'a> { fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> { maybe_whole!(self, NtArg, |x| x); - // If we see `ident :`, then we know that the argument is not just of the - // form `type`, which means we won't need to recover from parsing a - // pattern and so we don't need to store a parser snapshot. - let parser_snapshot_before_pat = if - self.look_ahead(1, |t| t.is_ident()) && - self.look_ahead(2, |t| t == &token::Colon) { - None - } else { - Some(self.clone()) - }; - - // We're going to try parsing the argument as a pattern (even if it's not - // allowed, such as for trait methods without bodies). This way we can provide - // better errors to the user. - let pat_arg: PResult<'a, (P, P)> = do catch { + let (pat, ty) = if require_name || self.is_named_argument() { + debug!("parse_arg_general parse_pat (require_name:{})", + require_name); let pat = self.parse_pat()?; + self.expect(&token::Colon)?; (pat, self.parse_ty()?) - }; + } else { + debug!("parse_arg_general ident_to_pat"); + + // If we see `ident :`, then we know that the argument is not just of the + // form `type`, which means we won't need to recover from parsing a + // pattern and so we don't need to store a parser snapshot. + let parser_snapshot_before_pat = if + self.look_ahead(1, |t| t.is_ident()) && + self.look_ahead(2, |t| t == &token::Colon) { + None + } else { + Some(self.clone()) + }; - match pat_arg { - Ok((pat, ty)) => { - Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID }) - } - Err(mut err) => { - match (require_name || self.is_named_argument(), parser_snapshot_before_pat) { - (true, _) | (_, None) => { - Err(err) - } - (false, Some(parser_snapshot_before_pat)) => { - 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, - }); - Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID }) - } + // 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, _> = do catch { + 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(pat.span, "patterns aren't allowed in trait methods"); + err.span_suggestion_short_with_applicability( + pat.span, + "give this argument a name or use an underscore to ignore it", + "_".to_owned(), + Applicability::MachineApplicable, + ); + err.emit(); + // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. + let pat = P(Pat { + node: PatKind::Wild, + span: pat.span, + id: ast::DUMMY_NODE_ID + }); + (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.unwrap()); + 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) } } - } + }; + + Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID }) } /// Parse a single function argument diff --git a/src/test/ui/E0642.stderr b/src/test/ui/E0642.stderr index 8c16b8b30cd53..b8e0496945a15 100644 --- a/src/test/ui/E0642.stderr +++ b/src/test/ui/E0642.stderr @@ -1,23 +1,22 @@ -error[E0642]: patterns aren't allowed in trait methods +error: patterns aren't allowed in trait methods --> $DIR/E0642.rs:12:12 | LL | fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in trait methods | ^^^^^^ -help: give this argument a name or use an underscore to ignore it instead of using a tuple pattern +help: give this argument a name or use an underscore to ignore it | LL | fn foo(_: (i32, i32)); //~ ERROR patterns aren't allowed in trait methods | ^ -error[E0642]: patterns aren't allowed in trait methods +error: patterns aren't allowed in trait methods --> $DIR/E0642.rs:16:12 | LL | fn bar((x, y): (i32, i32)) {} //~ ERROR patterns aren't allowed in trait methods | ^^^^^^ -help: give this argument a name or use an underscore to ignore it instead of using a tuple pattern +help: give this argument a name or use an underscore to ignore it | LL | fn bar(_: (i32, i32)) {} //~ ERROR patterns aren't allowed in trait methods | ^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0642`.