parser: Tweak function parameter parsing to avoid rollback on succesfull path
This commit is contained in:
parent
2fa1390f6c
commit
9784d3543f
1 changed files with 25 additions and 35 deletions
|
@ -1780,27 +1780,32 @@ impl<'a> Parser<'a> {
|
||||||
(pat, self.parse_ty()?)
|
(pat, self.parse_ty()?)
|
||||||
} else {
|
} else {
|
||||||
debug!("parse_arg_general ident_to_pat");
|
debug!("parse_arg_general ident_to_pat");
|
||||||
|
let parser_snapshot_before_ty = self.clone();
|
||||||
let parser_snapshot_before_pat = self.clone();
|
let mut ty = self.parse_ty();
|
||||||
|
if ty.is_ok() && self.token == token::Colon {
|
||||||
// Once we can use edition 2018 in the compiler,
|
// This wasn't actually a type, but a pattern looking like a type,
|
||||||
// replace this with real try blocks.
|
// so we are going to rollback and re-parse for recovery.
|
||||||
macro_rules! try_block {
|
ty = self.unexpected();
|
||||||
($($inside:tt)*) => (
|
|
||||||
(||{ ::std::ops::Try::from_ok({ $($inside)* }) })()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
match ty {
|
||||||
|
Ok(ty) => {
|
||||||
|
let ident = Ident::new(keywords::Invalid.name(), self.prev_span);
|
||||||
|
let pat = P(Pat {
|
||||||
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
node: PatKind::Ident(
|
||||||
|
BindingMode::ByValue(Mutability::Immutable), ident, None),
|
||||||
|
span: ty.span,
|
||||||
|
});
|
||||||
|
(pat, ty)
|
||||||
|
}
|
||||||
|
Err(mut err) => {
|
||||||
|
// Recover from attempting to parse the argument as a type without pattern.
|
||||||
|
err.cancel();
|
||||||
|
mem::replace(self, parser_snapshot_before_ty);
|
||||||
|
let pat = self.parse_pat()?;
|
||||||
|
self.expect(&token::Colon)?;
|
||||||
|
let ty = self.parse_ty()?;
|
||||||
|
|
||||||
// We're going to try parsing the argument as a pattern (even though it's not
|
|
||||||
// allowed). This way we can provide better errors to the user.
|
|
||||||
let pat_arg: PResult<'a, _> = try_block! {
|
|
||||||
let pat = self.parse_pat()?;
|
|
||||||
self.expect(&token::Colon)?;
|
|
||||||
(pat, self.parse_ty()?)
|
|
||||||
};
|
|
||||||
|
|
||||||
match pat_arg {
|
|
||||||
Ok((pat, ty)) => {
|
|
||||||
let mut err = self.diagnostic().struct_span_err_with_code(
|
let mut err = self.diagnostic().struct_span_err_with_code(
|
||||||
pat.span,
|
pat.span,
|
||||||
"patterns aren't allowed in methods without bodies",
|
"patterns aren't allowed in methods without bodies",
|
||||||
|
@ -1813,6 +1818,7 @@ impl<'a> Parser<'a> {
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
err.emit();
|
err.emit();
|
||||||
|
|
||||||
// Pretend the pattern is `_`, to avoid duplicate errors from AST validation.
|
// Pretend the pattern is `_`, to avoid duplicate errors from AST validation.
|
||||||
let pat = P(Pat {
|
let pat = P(Pat {
|
||||||
node: PatKind::Wild,
|
node: PatKind::Wild,
|
||||||
|
@ -1821,22 +1827,6 @@ impl<'a> Parser<'a> {
|
||||||
});
|
});
|
||||||
(pat, ty)
|
(pat, ty)
|
||||||
}
|
}
|
||||||
Err(mut err) => {
|
|
||||||
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,
|
|
||||||
});
|
|
||||||
(pat, ty)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue