diff options
| author | varkor <github@varkor.com> | 2018-08-06 18:14:57 +0100 |
|---|---|---|
| committer | varkor <github@varkor.com> | 2018-08-11 21:08:24 +0100 |
| commit | 235905c080bf953a522ff86d4fec6134ac4fb371 (patch) | |
| tree | 6cda1fc5a4ab5400f6cafde46dcd52ce16f8f898 /src | |
| parent | b05f0bec1a6f576cd275e52a8a0a0165fb25f77a (diff) | |
| download | rust-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.rs | 26 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 49 | ||||
| -rw-r--r-- | src/test/compile-fail/no-patterns-in-args-2.rs | 4 | ||||
| -rw-r--r-- | src/test/compile-fail/no-patterns-in-args-macro.rs | 2 | ||||
| -rw-r--r-- | src/test/ui/E0642.rs | 6 | ||||
| -rw-r--r-- | src/test/ui/E0642.stderr | 22 |
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`. |
