about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorvarkor <github@varkor.com>2018-08-06 18:14:57 +0100
committervarkor <github@varkor.com>2018-08-11 21:08:24 +0100
commit235905c080bf953a522ff86d4fec6134ac4fb371 (patch)
tree6cda1fc5a4ab5400f6cafde46dcd52ce16f8f898 /src
parentb05f0bec1a6f576cd275e52a8a0a0165fb25f77a (diff)
downloadrust-235905c080bf953a522ff86d4fec6134ac4fb371.tar.gz
rust-235905c080bf953a522ff86d4fec6134ac4fb371.zip
Fix handling of trait methods with bodies and improve efficiency
Diffstat (limited to 'src')
-rw-r--r--src/librustc_passes/ast_validation.rs26
-rw-r--r--src/libsyntax/parse/parser.rs49
-rw-r--r--src/test/compile-fail/no-patterns-in-args-2.rs4
-rw-r--r--src/test/compile-fail/no-patterns-in-args-macro.rs2
-rw-r--r--src/test/ui/E0642.rs6
-rw-r--r--src/test/ui/E0642.stderr22
6 files changed, 70 insertions, 39 deletions
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index c75ae07fe66..7022136f239 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -336,22 +336,24 @@ 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);
-                        if block.is_none() {
-                            self.check_decl_no_pat(&sig.decl, |span, mut_ident| {
-                                if mut_ident {
+                        self.check_decl_no_pat(&sig.decl, |span, mut_ident| {
+                            if mut_ident {
+                                if block.is_none() {
                                     self.session.buffer_lint(
                                         lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY,
                                         trait_item.id, span,
-                                        "patterns aren't allowed in methods without bodies");
-                                } else {
-                                    let mut err = struct_span_err!(self.session, span, E0642,
-                                        "patterns aren't allowed in methods without bodies");
-                                    err.span_suggestion(span,
-                                        "use an underscore to ignore the name", "_".to_owned());
-                                    err.emit();
+                                        "patterns aren't allowed in trait methods");
                                 }
-                            });
-                        }
+                            } 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 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 5a2fd5f0145..57eb1f52fb7 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1744,7 +1744,16 @@ impl<'a> Parser<'a> {
     fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> {
         maybe_whole!(self, NtArg, |x| x);
 
-        let parser_snapshot_before_pat = self.clone();
+        // If we see `ident :`, then we know that the argument is 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
@@ -1755,29 +1764,31 @@ impl<'a> Parser<'a> {
             (pat, self.parse_ty()?)
         };
 
-        let is_named_argument = self.is_named_argument();
         match pat_arg {
             Ok((pat, ty)) => {
                 Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID })
             }
             Err(mut err) => {
-                if require_name || is_named_argument {
-                    Err(err)
-                } else {
-                    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 })
+                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 })
+                    }
                 }
             }
         }
diff --git a/src/test/compile-fail/no-patterns-in-args-2.rs b/src/test/compile-fail/no-patterns-in-args-2.rs
index 4d2412c34a5..80e69679801 100644
--- a/src/test/compile-fail/no-patterns-in-args-2.rs
+++ b/src/test/compile-fail/no-patterns-in-args-2.rs
@@ -11,9 +11,9 @@
 #![deny(patterns_in_fns_without_body)]
 
 trait Tr {
-    fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in methods without bodies
+    fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in trait methods
                         //~^ WARN was previously accepted
-    fn f2(&arg: u8); //~ ERROR patterns aren't allowed in methods without bodies
+    fn f2(&arg: u8); //~ ERROR patterns aren't allowed in trait methods
     fn g1(arg: u8); // OK
     fn g2(_: u8); // OK
     #[allow(anonymous_parameters)]
diff --git a/src/test/compile-fail/no-patterns-in-args-macro.rs b/src/test/compile-fail/no-patterns-in-args-macro.rs
index f85ce8f57ea..546c40ecbd0 100644
--- a/src/test/compile-fail/no-patterns-in-args-macro.rs
+++ b/src/test/compile-fail/no-patterns-in-args-macro.rs
@@ -30,7 +30,7 @@ mod bad_pat {
     m!((bad, pat));
     //~^ ERROR patterns aren't allowed in function pointer types
     //~| ERROR patterns aren't allowed in foreign function declarations
-    //~| ERROR patterns aren't allowed in methods without bodies
+    //~| ERROR patterns aren't allowed in trait methods
 }
 
 fn main() {}
diff --git a/src/test/ui/E0642.rs b/src/test/ui/E0642.rs
index a09846cb3a1..837a9365271 100644
--- a/src/test/ui/E0642.rs
+++ b/src/test/ui/E0642.rs
@@ -9,7 +9,11 @@
 // except according to those terms.
 
 trait Foo {
-    fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in methods without bodies
+    fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in trait methods
+}
+
+trait Bar {
+    fn bar((x, y): (i32, i32)) {} //~ ERROR patterns aren't allowed in trait methods
 }
 
 fn main() {}
diff --git a/src/test/ui/E0642.stderr b/src/test/ui/E0642.stderr
index 5291c016c7f..07ec8b4cc2c 100644
--- a/src/test/ui/E0642.stderr
+++ b/src/test/ui/E0642.stderr
@@ -1,9 +1,23 @@
-error[E0642]: patterns aren't allowed in methods without bodies
+error[E0642]: 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 methods without bodies
-   |            ^^^^^^ help: use an underscore to ignore the name: `_`
+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 a tuple pattern
+   |
+LL |     fn foo(_: (i32, i32)); //~ ERROR patterns aren't allowed in trait methods
+   |            ^
+
+error[E0642]: 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 a tuple pattern
+   |
+LL |     fn bar(_: (i32, i32)) {} //~ ERROR patterns aren't allowed in trait methods
+   |            ^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0642`.