about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvarkor <github@varkor.com>2018-08-09 23:23:08 +0100
committervarkor <github@varkor.com>2018-08-11 21:08:24 +0100
commite4c3b49fe790dd23f32acace8157d897d31c0cb3 (patch)
tree2a7cc6356768ea527ea54277eea867dea2cefdcf
parenta478cd41e3f203ec531bfce7efb8fc602aad5c7d (diff)
Emit an error during parsing
-rw-r--r--src/librustc_passes/ast_validation.rs21
-rw-r--r--src/libsyntax/parse/parser.rs104
-rw-r--r--src/test/ui/E0642.stderr9
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`.