Skip to content

Commit 90a6954

Browse files
committed
Emit error for pattern arguments in trait methods
The error and check for this already existed, but the parser didn't try to parse trait method arguments as patterns, so the error was never emitted. This surfaces the error, so we get better errors than simple parse errors.
1 parent a77dfcc commit 90a6954

File tree

5 files changed

+71
-21
lines changed

5 files changed

+71
-21
lines changed

src/librustc_passes/diagnostics.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,19 @@ let result = loop { // ok!
261261
```
262262
"##,
263263

264+
E0642: r##"
265+
Trait methods currently cannot take patterns as arguments.
266+
267+
Example of erroneous code:
268+
269+
```compile_fail,E0642
270+
trait Foo {
271+
fn foo((x, y): (i32, i32)); // error: patterns aren't allowed
272+
// in methods without bodies
273+
}
274+
```
275+
"##,
276+
264277
E0695: r##"
265278
A `break` statement without a label appeared inside a labeled block.
266279
@@ -306,7 +319,6 @@ register_diagnostics! {
306319
E0561, // patterns aren't allowed in function pointer types
307320
E0567, // auto traits can not have generic parameters
308321
E0568, // auto traits can not have super traits
309-
E0642, // patterns aren't allowed in methods without bodies
310322
E0666, // nested `impl Trait` is illegal
311323
E0667, // `impl Trait` in projections
312324
E0696, // `continue` pointing to a labeled block

src/libsyntax/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#![feature(slice_sort_by_cached_key)]
2727
#![feature(str_escape)]
2828
#![feature(unicode_internals)]
29+
#![feature(catch_expr)]
2930

3031
#![recursion_limit="256"]
3132

src/libsyntax/parse/parser.rs

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,7 +1371,7 @@ impl<'a> Parser<'a> {
13711371
let ident = self.parse_ident()?;
13721372
let mut generics = self.parse_generics()?;
13731373

1374-
let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>|{
1374+
let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| {
13751375
// This is somewhat dubious; We don't want to allow
13761376
// argument names to be left off if there is a
13771377
// definition...
@@ -1744,30 +1744,43 @@ impl<'a> Parser<'a> {
17441744
fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> {
17451745
maybe_whole!(self, NtArg, |x| x);
17461746

1747-
let (pat, ty) = if require_name || self.is_named_argument() {
1748-
debug!("parse_arg_general parse_pat (require_name:{})",
1749-
require_name);
1750-
let pat = self.parse_pat()?;
1747+
let parser_snapshot_before_pat = self.clone();
17511748

1749+
// We're going to try parsing the argument as a pattern (even if it's not
1750+
// allowed, such as for trait methods without bodies). This way we can provide
1751+
// better errors to the user.
1752+
let pat_arg: PResult<'a, (P<Pat>, P<Ty>)> = do catch {
1753+
let pat = self.parse_pat()?;
17521754
self.expect(&token::Colon)?;
17531755
(pat, self.parse_ty()?)
1754-
} else {
1755-
debug!("parse_arg_general ident_to_pat");
1756-
let ident = Ident::new(keywords::Invalid.name(), self.prev_span);
1757-
let ty = self.parse_ty()?;
1758-
let pat = P(Pat {
1759-
id: ast::DUMMY_NODE_ID,
1760-
node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None),
1761-
span: ty.span,
1762-
});
1763-
(pat, ty)
17641756
};
17651757

1766-
Ok(Arg {
1767-
ty,
1768-
pat,
1769-
id: ast::DUMMY_NODE_ID,
1770-
})
1758+
let is_named_argument = self.is_named_argument();
1759+
match pat_arg {
1760+
Ok((pat, ty)) => {
1761+
Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID })
1762+
}
1763+
Err(mut err) => {
1764+
if require_name || is_named_argument {
1765+
Err(err)
1766+
} else {
1767+
err.cancel();
1768+
// Recover from attempting to parse the argument as a pattern. This means
1769+
// the type is alone, with no name, e.g. `fn foo(u32)`.
1770+
mem::replace(self, parser_snapshot_before_pat);
1771+
debug!("parse_arg_general ident_to_pat");
1772+
let ident = Ident::new(keywords::Invalid.name(), self.prev_span);
1773+
let ty = self.parse_ty()?;
1774+
let pat = P(Pat {
1775+
id: ast::DUMMY_NODE_ID,
1776+
node: PatKind::Ident(
1777+
BindingMode::ByValue(Mutability::Immutable), ident, None),
1778+
span: ty.span,
1779+
});
1780+
Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID })
1781+
}
1782+
}
1783+
}
17711784
}
17721785

17731786
/// Parse a single function argument

src/test/ui/E0642.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
trait Foo {
12+
fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in methods without bodies
13+
}
14+
15+
fn main() {}

src/test/ui/E0642.stderr

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0642]: patterns aren't allowed in methods without bodies
2+
--> $DIR/E0642.rs:12:12
3+
|
4+
LL | fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in methods without bodies
5+
| ^^^^^^
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0642`.

0 commit comments

Comments
 (0)