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:
parent
a77dfcc79f
commit
90a6954327
@ -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
|
||||||
|
@ -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"]
|
||||||
|
|
||||||
|
@ -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
15
src/test/ui/E0642.rs
Normal 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
9
src/test/ui/E0642.stderr
Normal 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`.
|
Loading…
Reference in New Issue
Block a user