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.
This commit is contained in:
varkor 2018-08-04 02:23:21 +01:00
parent a77dfcc79f
commit 90a6954327
5 changed files with 71 additions and 21 deletions

View File

@ -261,6 +261,19 @@ fn foo() {}
``` ```
"##, "##,
E0642: r##"
Trait methods currently cannot take patterns as arguments.
Example of erroneous code:
```compile_fail,E0642
trait Foo {
fn foo((x, y): (i32, i32)); // error: patterns aren't allowed
// in methods without bodies
}
```
"##,
E0695: r##" E0695: r##"
A `break` statement without a label appeared inside a labeled block. A `break` statement without a label appeared inside a labeled block.
@ -306,7 +319,6 @@ fn foo() {}
E0561, // patterns aren't allowed in function pointer types E0561, // patterns aren't allowed in function pointer types
E0567, // auto traits can not have generic parameters E0567, // auto traits can not have generic parameters
E0568, // auto traits can not have super traits E0568, // auto traits can not have super traits
E0642, // patterns aren't allowed in methods without bodies
E0666, // nested `impl Trait` is illegal E0666, // nested `impl Trait` is illegal
E0667, // `impl Trait` in projections E0667, // `impl Trait` in projections
E0696, // `continue` pointing to a labeled block E0696, // `continue` pointing to a labeled block

View File

@ -26,6 +26,7 @@
#![feature(slice_sort_by_cached_key)] #![feature(slice_sort_by_cached_key)]
#![feature(str_escape)] #![feature(str_escape)]
#![feature(unicode_internals)] #![feature(unicode_internals)]
#![feature(catch_expr)]
#![recursion_limit="256"] #![recursion_limit="256"]

View File

@ -1371,7 +1371,7 @@ fn parse_trait_item_(&mut self,
let ident = self.parse_ident()?; let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?; let mut generics = self.parse_generics()?;
let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>|{ let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| {
// This is somewhat dubious; We don't want to allow // This is somewhat dubious; We don't want to allow
// argument names to be left off if there is a // argument names to be left off if there is a
// definition... // definition...
@ -1744,30 +1744,43 @@ fn is_named_argument(&mut self) -> bool {
fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> { fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> {
maybe_whole!(self, NtArg, |x| x); maybe_whole!(self, NtArg, |x| x);
let (pat, ty) = if require_name || self.is_named_argument() { let parser_snapshot_before_pat = self.clone();
debug!("parse_arg_general parse_pat (require_name:{})",
require_name);
let pat = self.parse_pat()?;
// 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 = self.parse_pat()?;
self.expect(&token::Colon)?; self.expect(&token::Colon)?;
(pat, self.parse_ty()?) (pat, self.parse_ty()?)
} else {
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 { let is_named_argument = self.is_named_argument();
ty, match pat_arg {
pat, Ok((pat, ty)) => {
id: ast::DUMMY_NODE_ID, 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 })
}
}
}
} }
/// Parse a single function argument /// Parse a single function argument

15
src/test/ui/E0642.rs Normal file
View File

@ -0,0 +1,15 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait Foo {
fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in methods without bodies
}
fn main() {}

9
src/test/ui/E0642.stderr Normal file
View File

@ -0,0 +1,9 @@
error[E0642]: patterns aren't allowed in methods without bodies
--> $DIR/E0642.rs:12:12
|
LL | fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in methods without bodies
| ^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0642`.