diff options
| author | varkor <github@varkor.com> | 2018-08-09 23:23:08 +0100 |
|---|---|---|
| committer | varkor <github@varkor.com> | 2018-08-11 21:08:24 +0100 |
| commit | e4c3b49fe790dd23f32acace8157d897d31c0cb3 (patch) | |
| tree | 2a7cc6356768ea527ea54277eea867dea2cefdcf | |
| parent | a478cd41e3f203ec531bfce7efb8fc602aad5c7d (diff) | |
Emit an error during parsing
| -rw-r--r-- | src/librustc_passes/ast_validation.rs | 21 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 104 | ||||
| -rw-r--r-- | 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 2195331f465..e15dab404f4 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 a1dbe93fdfe..9a49d705c46 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<Pat>, P<Ty>)> = 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 8c16b8b30cd..b8e0496945a 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`. |
