pub fn eat_to_tokens(&mut self, kets: &[&token::Token]) {
let handler = self.diagnostic();
- self.parse_seq_to_before_tokens(kets,
- SeqSep::none(),
- TokenExpectType::Expect,
- |p| Ok(p.parse_token_tree()),
- |mut e| handler.cancel(&mut e));
+ if let Err(ref mut err) = self.parse_seq_to_before_tokens(kets,
+ SeqSep::none(),
+ TokenExpectType::Expect,
+ |p| Ok(p.parse_token_tree())) {
+ handler.cancel(err);
+ }
}
/// Parse a sequence, including the closing delimiter. The function
-> PResult<'a, Vec<T>> where
F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
{
- let val = self.parse_seq_to_before_end(ket, sep, f);
+ let val = self.parse_seq_to_before_end(ket, sep, f)?;
self.bump();
Ok(val)
}
ket: &token::Token,
sep: SeqSep,
f: F)
- -> Vec<T>
- where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>
+ -> PResult<'a, Vec<T>>
+ where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>
{
- self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f, |mut e| e.emit())
+ self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f)
}
- // `fe` is an error handler.
- fn parse_seq_to_before_tokens<T, F, Fe>(&mut self,
+ fn parse_seq_to_before_tokens<T, F>(&mut self,
kets: &[&token::Token],
sep: SeqSep,
expect: TokenExpectType,
- mut f: F,
- mut fe: Fe)
- -> Vec<T>
- where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
- Fe: FnMut(DiagnosticBuilder)
+ mut f: F)
+ -> PResult<'a, Vec<T>>
+ where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>
{
let mut first: bool = true;
let mut v = vec![];
if first {
first = false;
} else {
- if let Err(e) = self.expect(t) {
- fe(e);
+ if let Err(mut e) = self.expect(t) {
// Attempt to keep parsing if it was a similar separator
if let Some(ref tokens) = t.similar_tokens() {
if tokens.contains(&self.token) {
self.bump();
}
}
+ e.emit();
// Attempt to keep parsing if it was an omitted separator
match f(self) {
Ok(t) => {
break;
}
- match f(self) {
- Ok(t) => v.push(t),
- Err(e) => {
- fe(e);
- break;
- }
- }
+ let t = f(self)?;
+ v.push(t);
}
- v
+ Ok(v)
}
/// Parse a sequence, including the closing delimiter. The function
F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
{
self.expect(bra)?;
- let result = self.parse_seq_to_before_end(ket, sep, f);
+ let result = self.parse_seq_to_before_end(ket, sep, f)?;
if self.token == *ket {
self.bump();
}
{
let lo = self.span;
self.expect(bra)?;
- let result = self.parse_seq_to_before_end(ket, sep, f);
+ let result = self.parse_seq_to_before_end(ket, sep, f)?;
let hi = self.span;
self.bump();
Ok(respan(lo.to(hi), result))
};
let span = lo.to(self.prev_span);
- let ty = Ty { node: node, span: span, id: ast::DUMMY_NODE_ID };
+ let ty = Ty { node, span, id: ast::DUMMY_NODE_ID };
// Try to recover from use of `+` with incorrect priority.
self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?;
self.parse_path(style)
}
- fn parse_path_segments(&mut self, segments: &mut Vec<PathSegment>, style: PathStyle,
- enable_warning: bool) -> PResult<'a, ()> {
+ fn parse_path_segments(&mut self,
+ segments: &mut Vec<PathSegment>,
+ style: PathStyle,
+ enable_warning: bool)
+ -> PResult<'a, ()> {
loop {
segments.push(self.parse_path_segment(style, enable_warning)?);
} else {
// `(T, U) -> R`
self.bump(); // `(`
- let inputs = self.parse_seq_to_end(&token::CloseDelim(token::Paren),
- SeqSep::trailing_allowed(token::Comma),
- |p| p.parse_ty())?;
+ let inputs = self.parse_seq_to_before_tokens(
+ &[&token::CloseDelim(token::Paren)],
+ SeqSep::trailing_allowed(token::Comma),
+ TokenExpectType::Expect,
+ |p| p.parse_ty())?;
+ self.bump(); // `)`
let output = if self.eat(&token::RArrow) {
Some(self.parse_ty_no_plus()?)
} else {
}
/// Parse the RHS of a local variable declaration (e.g. '= 14;')
- fn parse_initializer(&mut self) -> PResult<'a, Option<P<Expr>>> {
+ fn parse_initializer(&mut self, skip_eq: bool) -> PResult<'a, Option<P<Expr>>> {
if self.check(&token::Eq) {
self.bump();
Ok(Some(self.parse_expr()?))
+ } else if skip_eq {
+ Ok(Some(self.parse_expr()?))
} else {
Ok(None)
}
let lo = self.prev_span;
let pat = self.parse_pat()?;
- let ty = if self.eat(&token::Colon) {
- Some(self.parse_ty()?)
+ let (err, ty) = if self.eat(&token::Colon) {
+ // Save the state of the parser before parsing type normally, in case there is a `:`
+ // instead of an `=` typo.
+ let parser_snapshot_before_type = self.clone();
+ let colon_sp = self.prev_span;
+ match self.parse_ty() {
+ Ok(ty) => (None, Some(ty)),
+ Err(mut err) => {
+ // Rewind to before attempting to parse the type and continue parsing
+ let parser_snapshot_after_type = self.clone();
+ mem::replace(self, parser_snapshot_before_type);
+
+ let snippet = self.sess.codemap().span_to_snippet(pat.span).unwrap();
+ err.span_label(pat.span, format!("while parsing the type for `{}`", snippet));
+ (Some((parser_snapshot_after_type, colon_sp, err)), None)
+ }
+ }
} else {
- None
+ (None, None)
+ };
+ let init = match (self.parse_initializer(err.is_some()), err) {
+ (Ok(init), None) => { // init parsed, ty parsed
+ init
+ }
+ (Ok(init), Some((_, colon_sp, mut err))) => { // init parsed, ty error
+ // Could parse the type as if it were the initializer, it is likely there was a
+ // typo in the code: `:` instead of `=`. Add suggestion and emit the error.
+ err.span_suggestion_short(colon_sp,
+ "use `=` if you meant to assign",
+ "=".to_string());
+ err.emit();
+ // As this was parsed successfuly, continue as if the code has been fixed for the
+ // rest of the file. It will still fail due to the emitted error, but we avoid
+ // extra noise.
+ init
+ }
+ (Err(mut init_err), Some((snapshot, _, ty_err))) => { // init error, ty error
+ init_err.cancel();
+ // Couldn't parse the type nor the initializer, only raise the type error and
+ // return to the parser state before parsing the type as the initializer.
+ // let x: <parse_error>;
+ mem::replace(self, snapshot);
+ return Err(ty_err);
+ }
+ (Err(err), None) => { // init error, ty parsed
+ // Couldn't parse the initializer and we're not attempting to recover a failed
+ // parse of the type, return the error.
+ return Err(err);
+ }
};
- let init = self.parse_initializer()?;
let hi = if self.token == token::Semi {
self.span
} else {
} else if self.eat(&token::Comma) {
let mut fn_inputs = vec![self_arg];
fn_inputs.append(&mut self.parse_seq_to_before_end(
- &token::CloseDelim(token::Paren), sep, parse_arg_fn)
+ &token::CloseDelim(token::Paren), sep, parse_arg_fn)?
);
fn_inputs
} else {
return self.unexpected();
}
} else {
- self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)
+ self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)?
};
// Parse closing paren and return type.
&[&token::BinOp(token::Or), &token::OrOr],
SeqSep::trailing_allowed(token::Comma),
TokenExpectType::NoExpect,
- |p| p.parse_fn_block_arg(),
- |mut e| e.emit()
- );
+ |p| p.parse_fn_block_arg()
+ )?;
self.expect_or()?;
args
}