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

@@ -1371,7 +1371,7 @@ impl<'a> Parser<'a> {
let ident = self.parse_ident()?;
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
// argument names to be left off if there is a
// definition...
@@ -1744,30 +1744,43 @@ impl<'a> Parser<'a> {
fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> {
maybe_whole!(self, NtArg, |x| x);
let (pat, ty) = if require_name || self.is_named_argument() {
debug!("parse_arg_general parse_pat (require_name:{})",
require_name);
let pat = self.parse_pat()?;
let parser_snapshot_before_pat = 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
// 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)?;
(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 {
ty,
pat,
id: ast::DUMMY_NODE_ID,
})
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 })
}
}
}
}
/// Parse a single function argument