syntax: reorder param parsing to make more sense.
This commit is contained in:
parent
0492302dbd
commit
347deac455
1 changed files with 153 additions and 153 deletions
|
@ -954,106 +954,6 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_named_param(&self) -> bool {
|
|
||||||
let offset = match self.token.kind {
|
|
||||||
token::Interpolated(ref nt) => match **nt {
|
|
||||||
token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
|
|
||||||
_ => 0,
|
|
||||||
}
|
|
||||||
token::BinOp(token::And) | token::AndAnd => 1,
|
|
||||||
_ if self.token.is_keyword(kw::Mut) => 1,
|
|
||||||
_ => 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.look_ahead(offset, |t| t.is_ident()) &&
|
|
||||||
self.look_ahead(offset + 1, |t| t == &token::Colon)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Skips unexpected attributes and doc comments in this position and emits an appropriate
|
|
||||||
/// error.
|
|
||||||
/// This version of parse param doesn't necessarily require identifier names.
|
|
||||||
fn parse_param_general(
|
|
||||||
&mut self,
|
|
||||||
is_self_allowed: bool,
|
|
||||||
is_trait_item: bool,
|
|
||||||
allow_c_variadic: bool,
|
|
||||||
is_name_required: impl Fn(&token::Token) -> bool,
|
|
||||||
) -> PResult<'a, Param> {
|
|
||||||
let lo = self.token.span;
|
|
||||||
let attrs = self.parse_outer_attributes()?;
|
|
||||||
|
|
||||||
// Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
|
|
||||||
if let Some(mut param) = self.parse_self_param()? {
|
|
||||||
param.attrs = attrs.into();
|
|
||||||
return if is_self_allowed {
|
|
||||||
Ok(param)
|
|
||||||
} else {
|
|
||||||
self.recover_bad_self_param(param, is_trait_item)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let is_name_required = is_name_required(&self.token);
|
|
||||||
let (pat, ty) = if is_name_required || self.is_named_param() {
|
|
||||||
debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
|
|
||||||
|
|
||||||
let pat = self.parse_fn_param_pat()?;
|
|
||||||
if let Err(mut err) = self.expect(&token::Colon) {
|
|
||||||
if let Some(ident) = self.parameter_without_type(
|
|
||||||
&mut err,
|
|
||||||
pat,
|
|
||||||
is_name_required,
|
|
||||||
is_trait_item,
|
|
||||||
) {
|
|
||||||
err.emit();
|
|
||||||
return Ok(dummy_arg(ident));
|
|
||||||
} else {
|
|
||||||
return Err(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.eat_incorrect_doc_comment_for_param_type();
|
|
||||||
(pat, self.parse_ty_common(true, true, allow_c_variadic)?)
|
|
||||||
} else {
|
|
||||||
debug!("parse_param_general ident_to_pat");
|
|
||||||
let parser_snapshot_before_ty = self.clone();
|
|
||||||
self.eat_incorrect_doc_comment_for_param_type();
|
|
||||||
let mut ty = self.parse_ty_common(true, true, allow_c_variadic);
|
|
||||||
if ty.is_ok() && self.token != token::Comma &&
|
|
||||||
self.token != token::CloseDelim(token::Paren) {
|
|
||||||
// This wasn't actually a type, but a pattern looking like a type,
|
|
||||||
// so we are going to rollback and re-parse for recovery.
|
|
||||||
ty = self.unexpected();
|
|
||||||
}
|
|
||||||
match ty {
|
|
||||||
Ok(ty) => {
|
|
||||||
let ident = Ident::new(kw::Invalid, self.prev_span);
|
|
||||||
let bm = BindingMode::ByValue(Mutability::Immutable);
|
|
||||||
let pat = self.mk_pat_ident(ty.span, bm, ident);
|
|
||||||
(pat, ty)
|
|
||||||
}
|
|
||||||
// If this is a C-variadic argument and we hit an error, return the error.
|
|
||||||
Err(err) if self.token == token::DotDotDot => return Err(err),
|
|
||||||
// Recover from attempting to parse the argument as a type without pattern.
|
|
||||||
Err(mut err) => {
|
|
||||||
err.cancel();
|
|
||||||
mem::replace(self, parser_snapshot_before_ty);
|
|
||||||
self.recover_arg_parse()?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let span = lo.to(self.token.span);
|
|
||||||
|
|
||||||
Ok(Param {
|
|
||||||
attrs: attrs.into(),
|
|
||||||
id: ast::DUMMY_NODE_ID,
|
|
||||||
is_placeholder: false,
|
|
||||||
pat,
|
|
||||||
span,
|
|
||||||
ty,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses mutability (`mut` or nothing).
|
/// Parses mutability (`mut` or nothing).
|
||||||
fn parse_mutability(&mut self) -> Mutability {
|
fn parse_mutability(&mut self) -> Mutability {
|
||||||
if self.eat_keyword(kw::Mut) {
|
if self.eat_keyword(kw::Mut) {
|
||||||
|
@ -1267,49 +1167,112 @@ impl<'a> Parser<'a> {
|
||||||
Ok(params)
|
Ok(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_isolated_self(&self, n: usize) -> bool {
|
/// Parses the parameter list and result type of a function that may have a `self` parameter.
|
||||||
self.is_keyword_ahead(n, &[kw::SelfLower])
|
fn parse_fn_decl_with_self(
|
||||||
&& self.look_ahead(n + 1, |t| t != &token::ModSep)
|
&mut self,
|
||||||
|
is_name_required: impl Copy + Fn(&token::Token) -> bool,
|
||||||
|
) -> PResult<'a, P<FnDecl>> {
|
||||||
|
// Parse the arguments, starting out with `self` being allowed...
|
||||||
|
let mut is_self_allowed = true;
|
||||||
|
let (mut inputs, _): (Vec<_>, _) = self.parse_paren_comma_seq(|p| {
|
||||||
|
let res = p.parse_param_general(is_self_allowed, true, false, is_name_required);
|
||||||
|
// ...but now that we've parsed the first argument, `self` is no longer allowed.
|
||||||
|
is_self_allowed = false;
|
||||||
|
res
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Replace duplicated recovered params with `_` pattern to avoid unecessary errors.
|
||||||
|
self.deduplicate_recovered_params_names(&mut inputs);
|
||||||
|
|
||||||
|
Ok(P(FnDecl {
|
||||||
|
inputs,
|
||||||
|
output: self.parse_ret_ty(true)?,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_isolated_mut_self(&self, n: usize) -> bool {
|
/// Skips unexpected attributes and doc comments in this position and emits an appropriate
|
||||||
self.is_keyword_ahead(n, &[kw::Mut])
|
/// error.
|
||||||
&& self.is_isolated_self(n + 1)
|
/// This version of parse param doesn't necessarily require identifier names.
|
||||||
}
|
fn parse_param_general(
|
||||||
|
&mut self,
|
||||||
|
is_self_allowed: bool,
|
||||||
|
is_trait_item: bool,
|
||||||
|
allow_c_variadic: bool,
|
||||||
|
is_name_required: impl Fn(&token::Token) -> bool,
|
||||||
|
) -> PResult<'a, Param> {
|
||||||
|
let lo = self.token.span;
|
||||||
|
let attrs = self.parse_outer_attributes()?;
|
||||||
|
|
||||||
fn expect_self_ident(&mut self) -> Ident {
|
// Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
|
||||||
match self.token.kind {
|
if let Some(mut param) = self.parse_self_param()? {
|
||||||
// Preserve hygienic context.
|
param.attrs = attrs.into();
|
||||||
token::Ident(name, _) => {
|
return if is_self_allowed {
|
||||||
let span = self.token.span;
|
Ok(param)
|
||||||
self.bump();
|
|
||||||
Ident::new(name, span)
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Recover for the grammar `*self`, `*const self`, and `*mut self`.
|
|
||||||
fn recover_self_ptr(&mut self) -> PResult<'a, (ast::SelfKind, Ident, Span)> {
|
|
||||||
let msg = "cannot pass `self` by raw pointer";
|
|
||||||
let span = self.token.span;
|
|
||||||
self.struct_span_err(span, msg)
|
|
||||||
.span_label(span, msg)
|
|
||||||
.emit();
|
|
||||||
|
|
||||||
Ok((SelfKind::Value(Mutability::Immutable), self.expect_self_ident(), self.prev_span))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse `self` or `self: TYPE`. We already know the current token is `self`.
|
|
||||||
fn parse_self_possibly_typed(&mut self, m: Mutability) -> PResult<'a, (SelfKind, Ident, Span)> {
|
|
||||||
let eself_ident = self.expect_self_ident();
|
|
||||||
let eself_hi = self.prev_span;
|
|
||||||
let eself = if self.eat(&token::Colon) {
|
|
||||||
SelfKind::Explicit(self.parse_ty()?, m)
|
|
||||||
} else {
|
} else {
|
||||||
SelfKind::Value(m)
|
self.recover_bad_self_param(param, is_trait_item)
|
||||||
};
|
};
|
||||||
Ok((eself, eself_ident, eself_hi))
|
}
|
||||||
|
|
||||||
|
let is_name_required = is_name_required(&self.token);
|
||||||
|
let (pat, ty) = if is_name_required || self.is_named_param() {
|
||||||
|
debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
|
||||||
|
|
||||||
|
let pat = self.parse_fn_param_pat()?;
|
||||||
|
if let Err(mut err) = self.expect(&token::Colon) {
|
||||||
|
if let Some(ident) = self.parameter_without_type(
|
||||||
|
&mut err,
|
||||||
|
pat,
|
||||||
|
is_name_required,
|
||||||
|
is_trait_item,
|
||||||
|
) {
|
||||||
|
err.emit();
|
||||||
|
return Ok(dummy_arg(ident));
|
||||||
|
} else {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.eat_incorrect_doc_comment_for_param_type();
|
||||||
|
(pat, self.parse_ty_common(true, true, allow_c_variadic)?)
|
||||||
|
} else {
|
||||||
|
debug!("parse_param_general ident_to_pat");
|
||||||
|
let parser_snapshot_before_ty = self.clone();
|
||||||
|
self.eat_incorrect_doc_comment_for_param_type();
|
||||||
|
let mut ty = self.parse_ty_common(true, true, allow_c_variadic);
|
||||||
|
if ty.is_ok() && self.token != token::Comma &&
|
||||||
|
self.token != token::CloseDelim(token::Paren) {
|
||||||
|
// This wasn't actually a type, but a pattern looking like a type,
|
||||||
|
// so we are going to rollback and re-parse for recovery.
|
||||||
|
ty = self.unexpected();
|
||||||
|
}
|
||||||
|
match ty {
|
||||||
|
Ok(ty) => {
|
||||||
|
let ident = Ident::new(kw::Invalid, self.prev_span);
|
||||||
|
let bm = BindingMode::ByValue(Mutability::Immutable);
|
||||||
|
let pat = self.mk_pat_ident(ty.span, bm, ident);
|
||||||
|
(pat, ty)
|
||||||
|
}
|
||||||
|
// If this is a C-variadic argument and we hit an error, return the error.
|
||||||
|
Err(err) if self.token == token::DotDotDot => return Err(err),
|
||||||
|
// Recover from attempting to parse the argument as a type without pattern.
|
||||||
|
Err(mut err) => {
|
||||||
|
err.cancel();
|
||||||
|
mem::replace(self, parser_snapshot_before_ty);
|
||||||
|
self.recover_arg_parse()?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let span = lo.to(self.token.span);
|
||||||
|
|
||||||
|
Ok(Param {
|
||||||
|
attrs: attrs.into(),
|
||||||
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
is_placeholder: false,
|
||||||
|
pat,
|
||||||
|
span,
|
||||||
|
ty,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the parsed optional self parameter and whether a self shortcut was used.
|
/// Returns the parsed optional self parameter and whether a self shortcut was used.
|
||||||
|
@ -1378,27 +1341,64 @@ impl<'a> Parser<'a> {
|
||||||
Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident)))
|
Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses the parameter list and result type of a function that may have a `self` parameter.
|
fn is_named_param(&self) -> bool {
|
||||||
fn parse_fn_decl_with_self(
|
let offset = match self.token.kind {
|
||||||
&mut self,
|
token::Interpolated(ref nt) => match **nt {
|
||||||
is_name_required: impl Copy + Fn(&token::Token) -> bool,
|
token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
|
||||||
) -> PResult<'a, P<FnDecl>> {
|
_ => 0,
|
||||||
// Parse the arguments, starting out with `self` being allowed...
|
}
|
||||||
let mut is_self_allowed = true;
|
token::BinOp(token::And) | token::AndAnd => 1,
|
||||||
let (mut inputs, _): (Vec<_>, _) = self.parse_paren_comma_seq(|p| {
|
_ if self.token.is_keyword(kw::Mut) => 1,
|
||||||
let res = p.parse_param_general(is_self_allowed, true, false, is_name_required);
|
_ => 0,
|
||||||
// ...but now that we've parsed the first argument, `self` is no longer allowed.
|
};
|
||||||
is_self_allowed = false;
|
|
||||||
res
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Replace duplicated recovered params with `_` pattern to avoid unecessary errors.
|
self.look_ahead(offset, |t| t.is_ident()) &&
|
||||||
self.deduplicate_recovered_params_names(&mut inputs);
|
self.look_ahead(offset + 1, |t| t == &token::Colon)
|
||||||
|
}
|
||||||
|
|
||||||
Ok(P(FnDecl {
|
fn is_isolated_self(&self, n: usize) -> bool {
|
||||||
inputs,
|
self.is_keyword_ahead(n, &[kw::SelfLower])
|
||||||
output: self.parse_ret_ty(true)?,
|
&& self.look_ahead(n + 1, |t| t != &token::ModSep)
|
||||||
}))
|
}
|
||||||
|
|
||||||
|
fn is_isolated_mut_self(&self, n: usize) -> bool {
|
||||||
|
self.is_keyword_ahead(n, &[kw::Mut])
|
||||||
|
&& self.is_isolated_self(n + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect_self_ident(&mut self) -> Ident {
|
||||||
|
match self.token.kind {
|
||||||
|
// Preserve hygienic context.
|
||||||
|
token::Ident(name, _) => {
|
||||||
|
let span = self.token.span;
|
||||||
|
self.bump();
|
||||||
|
Ident::new(name, span)
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Recover for the grammar `*self`, `*const self`, and `*mut self`.
|
||||||
|
fn recover_self_ptr(&mut self) -> PResult<'a, (ast::SelfKind, Ident, Span)> {
|
||||||
|
let msg = "cannot pass `self` by raw pointer";
|
||||||
|
let span = self.token.span;
|
||||||
|
self.struct_span_err(span, msg)
|
||||||
|
.span_label(span, msg)
|
||||||
|
.emit();
|
||||||
|
|
||||||
|
Ok((SelfKind::Value(Mutability::Immutable), self.expect_self_ident(), self.prev_span))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse `self` or `self: TYPE`. We already know the current token is `self`.
|
||||||
|
fn parse_self_possibly_typed(&mut self, m: Mutability) -> PResult<'a, (SelfKind, Ident, Span)> {
|
||||||
|
let eself_ident = self.expect_self_ident();
|
||||||
|
let eself_hi = self.prev_span;
|
||||||
|
let eself = if self.eat(&token::Colon) {
|
||||||
|
SelfKind::Explicit(self.parse_ty()?, m)
|
||||||
|
} else {
|
||||||
|
SelfKind::Value(m)
|
||||||
|
};
|
||||||
|
Ok((eself, eself_ident, eself_hi))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_crate_vis(&self) -> bool {
|
fn is_crate_vis(&self) -> bool {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue